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/proxy_controllable.h"
104 #include "ardour/recent_sessions.h"
105 #include "ardour/region_factory.h"
106 #include "ardour/route_group.h"
107 #include "ardour/send.h"
108 #include "ardour/session.h"
109 #include "ardour/session_directory.h"
110 #include "ardour/session_metadata.h"
111 #include "ardour/session_playlists.h"
112 #include "ardour/session_state_utils.h"
113 #include "ardour/silentfilesource.h"
114 #include "ardour/sndfilesource.h"
115 #include "ardour/source_factory.h"
116 #include "ardour/speakers.h"
117 #include "ardour/template_utils.h"
118 #include "ardour/tempo.h"
119 #include "ardour/ticker.h"
120 #include "ardour/user_bundle.h"
122 #include "control_protocol/control_protocol.h"
128 using namespace ARDOUR;
132 Session::pre_engine_init (string fullpath)
134 if (fullpath.empty()) {
136 throw failed_constructor();
139 /* discover canonical fullpath */
141 _path = canonical_path(fullpath);
145 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
147 /* finish initialization that can't be done in a normal C++ constructor
151 timerclear (&last_mmc_step);
152 g_atomic_int_set (&processing_prohibited, 0);
153 g_atomic_int_set (&_record_status, Disabled);
154 g_atomic_int_set (&_playback_load, 100);
155 g_atomic_int_set (&_capture_load, 100);
157 _all_route_group->set_active (true, this);
158 interpolation.add_channel_to (0, 0);
160 if (config.get_use_video_sync()) {
161 waiting_for_sync_offset = true;
163 waiting_for_sync_offset = false;
166 last_rr_session_dir = session_dirs.begin();
168 set_history_depth (Config->get_history_depth());
170 /* default: assume simple stereo speaker configuration */
172 _speakers->setup_default_speakers (2);
174 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
175 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
176 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
177 add_controllable (_solo_cut_control);
179 /* These are all static "per-class" signals */
181 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
182 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
183 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
184 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
185 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
187 /* stop IO objects from doing stuff until we're ready for them */
189 Delivery::disable_panners ();
190 IO::disable_connecting ();
192 AudioFileSource::set_peak_dir (_session_dir->peak_path());
196 Session::post_engine_init ()
198 BootMessage (_("Set block size and sample rate"));
200 set_block_size (_engine.samples_per_cycle());
201 set_frame_rate (_engine.sample_rate());
203 BootMessage (_("Using configuration"));
205 _midi_ports = new MidiPortManager;
207 MIDISceneChanger* msc;
209 _scene_changer = msc = new MIDISceneChanger (*this);
210 msc->set_input_port (scene_input_port());
211 msc->set_output_port (scene_out());
213 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
214 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
216 setup_midi_machine_control ();
218 if (_butler->start_thread()) {
222 if (start_midi_thread ()) {
226 setup_click_sounds (0);
227 setup_midi_control ();
229 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
230 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
233 /* tempo map requires sample rate knowledge */
236 _tempo_map = new TempoMap (_current_frame_rate);
237 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
239 /* MidiClock requires a tempo map */
241 midi_clock = new MidiClockTicker ();
242 midi_clock->set_session (this);
244 /* crossfades require sample rate knowledge */
246 SndFileSource::setup_standard_crossfades (*this, frame_rate());
247 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
249 AudioDiskstream::allocate_working_buffers();
250 refresh_disk_space ();
252 /* we're finally ready to call set_state() ... all objects have
253 * been created, the engine is running.
257 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
261 // set_state() will call setup_raid_path(), but if it's a new session we need
262 // to call setup_raid_path() here.
263 setup_raid_path (_path);
268 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
269 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
271 Config->map_parameters (ff);
272 config.map_parameters (ft);
274 /* Reset all panners */
276 Delivery::reset_panners ();
278 /* this will cause the CPM to instantiate any protocols that are in use
279 * (or mandatory), which will pass it this Session, and then call
280 * set_state() on each instantiated protocol to match stored state.
283 ControlProtocolManager::instance().set_session (this);
285 /* This must be done after the ControlProtocolManager set_session above,
286 as it will set states for ports which the ControlProtocolManager creates.
289 // XXX set state of MIDI::Port's
290 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
292 /* And this must be done after the MIDI::Manager::set_port_states as
293 * it will try to make connections whose details are loaded by set_port_states.
298 /* Let control protocols know that we are now all connected, so they
299 * could start talking to surfaces if they want to.
302 ControlProtocolManager::instance().midi_connectivity_established ();
304 if (_is_new && !no_auto_connect()) {
305 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
306 auto_connect_master_bus ();
309 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
311 /* update latencies */
313 initialize_latencies ();
315 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
316 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
317 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
319 } catch (AudioEngine::PortRegistrationFailure& err) {
320 /* handle this one in a different way than all others, so that its clear what happened */
321 error << err.what() << endmsg;
327 BootMessage (_("Reset Remote Controls"));
329 // send_full_time_code (0);
330 _engine.transport_locate (0);
332 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
333 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
335 MIDI::Name::MidiPatchManager::instance().set_session (this);
338 /* initial program change will be delivered later; see ::config_changed() */
340 _state_of_the_state = Clean;
342 Port::set_connecting_blocked (false);
344 DirtyChanged (); /* EMIT SIGNAL */
348 } else if (state_was_pending) {
350 remove_pending_capture_state ();
351 state_was_pending = false;
358 Session::raid_path () const
360 Searchpath raid_search_path;
362 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
363 raid_search_path += (*i).path;
366 return raid_search_path.to_string ();
370 Session::setup_raid_path (string path)
379 session_dirs.clear ();
381 Searchpath search_path(path);
382 Searchpath sound_search_path;
383 Searchpath midi_search_path;
385 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
387 sp.blocks = 0; // not needed
388 session_dirs.push_back (sp);
390 SessionDirectory sdir(sp.path);
392 sound_search_path += sdir.sound_path ();
393 midi_search_path += sdir.midi_path ();
396 // reset the round-robin soundfile path thingie
397 last_rr_session_dir = session_dirs.begin();
401 Session::path_is_within_session (const std::string& path)
403 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
404 if (PBD::path_is_within (i->path, path)) {
412 Session::ensure_subdirs ()
416 dir = session_directory().peak_path();
418 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
419 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
423 dir = session_directory().sound_path();
425 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
426 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
430 dir = session_directory().midi_path();
432 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
433 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
437 dir = session_directory().dead_path();
439 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
440 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
444 dir = session_directory().export_path();
446 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
447 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
451 dir = analysis_dir ();
453 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
454 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
458 dir = plugins_dir ();
460 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
461 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
465 dir = externals_dir ();
467 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
468 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
475 /** @param session_template directory containing session template, or empty.
476 * Caller must not hold process lock.
479 Session::create (const string& session_template, BusProfile* bus_profile)
481 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
482 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
486 if (ensure_subdirs ()) {
490 _writable = exists_and_writable (_path);
492 if (!session_template.empty()) {
493 std::string in_path = session_template_dir_to_file (session_template);
495 ifstream in(in_path.c_str());
498 /* no need to call legalize_for_path() since the string
499 * in session_template is already a legal path name
501 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
503 ofstream out(out_path.c_str());
509 /* Copy plugin state files from template to new session */
510 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
511 copy_recurse (template_plugins, plugins_dir ());
516 error << string_compose (_("Could not open %1 for writing session template"), out_path)
522 error << string_compose (_("Could not open session template %1 for reading"), in_path)
529 /* set initial start + end point */
531 _state_of_the_state = Clean;
533 /* set up Master Out and Control Out if necessary */
538 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
540 if (bus_profile->master_out_channels) {
541 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
545 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
546 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
549 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
550 r->input()->ensure_io (count, false, this);
551 r->output()->ensure_io (count, false, this);
557 /* prohibit auto-connect to master, because there isn't one */
558 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
562 add_routes (rl, false, false, false);
565 /* this allows the user to override settings with an environment variable.
568 if (no_auto_connect()) {
569 bus_profile->input_ac = AutoConnectOption (0);
570 bus_profile->output_ac = AutoConnectOption (0);
573 Config->set_input_auto_connect (bus_profile->input_ac);
574 Config->set_output_auto_connect (bus_profile->output_ac);
577 if (Config->get_use_monitor_bus() && bus_profile) {
578 add_monitor_section ();
585 Session::maybe_write_autosave()
587 if (dirty() && record_status() != Recording) {
588 save_state("", true);
593 Session::remove_pending_capture_state ()
595 std::string pending_state_file_path(_session_dir->root_path());
597 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
599 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
601 if (g_remove (pending_state_file_path.c_str()) != 0) {
602 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
603 pending_state_file_path, g_strerror (errno)) << endmsg;
607 /** Rename a state file.
608 * @param old_name Old snapshot name.
609 * @param new_name New snapshot name.
612 Session::rename_state (string old_name, string new_name)
614 if (old_name == _current_snapshot_name || old_name == _name) {
615 /* refuse to rename the current snapshot or the "main" one */
619 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
620 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
622 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
623 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
625 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
626 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
627 old_name, new_name, g_strerror(errno)) << endmsg;
631 /** Remove a state file.
632 * @param snapshot_name Snapshot name.
635 Session::remove_state (string snapshot_name)
637 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
638 // refuse to remove the current snapshot or the "main" one
642 std::string xml_path(_session_dir->root_path());
644 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
646 if (!create_backup_file (xml_path)) {
647 // don't remove it if a backup can't be made
648 // create_backup_file will log the error.
653 if (g_remove (xml_path.c_str()) != 0) {
654 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
655 xml_path, g_strerror (errno)) << endmsg;
659 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
661 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
664 std::string xml_path(_session_dir->root_path());
666 /* prevent concurrent saves from different threads */
668 Glib::Threads::Mutex::Lock lm (save_state_lock);
670 if (!_writable || (_state_of_the_state & CannotSave)) {
674 if (g_atomic_int_get(&_suspend_save)) {
678 _save_queued = false;
680 if (!_engine.connected ()) {
681 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
687 /* tell sources we're saving first, in case they write out to a new file
688 * which should be saved with the state rather than the old one */
689 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
691 i->second->session_saved();
692 } catch (Evoral::SMF::FileError& e) {
693 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
697 SessionSaveUnderway (); /* EMIT SIGNAL */
700 tree.set_root (&get_template());
702 tree.set_root (&get_state());
705 if (snapshot_name.empty()) {
706 snapshot_name = _current_snapshot_name;
707 } else if (switch_to_snapshot) {
708 _current_snapshot_name = snapshot_name;
713 /* proper save: use statefile_suffix (.ardour in English) */
715 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
717 /* make a backup copy of the old file */
719 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
720 // create_backup_file will log the error
726 /* pending save: use pending_suffix (.pending in English) */
727 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
730 std::string tmp_path(_session_dir->root_path());
731 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
733 cerr << "actually writing state to " << tmp_path << endl;
735 if (!tree.write (tmp_path)) {
736 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
737 if (g_remove (tmp_path.c_str()) != 0) {
738 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
739 tmp_path, g_strerror (errno)) << endmsg;
745 cerr << "renaming state to " << xml_path << endl;
747 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
748 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
749 tmp_path, xml_path, g_strerror(errno)) << endmsg;
750 if (g_remove (tmp_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
752 tmp_path, g_strerror (errno)) << endmsg;
760 save_history (snapshot_name);
762 bool was_dirty = dirty();
764 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
767 DirtyChanged (); /* EMIT SIGNAL */
770 StateSaved (snapshot_name); /* EMIT SIGNAL */
777 Session::restore_state (string snapshot_name)
779 if (load_state (snapshot_name) == 0) {
780 set_state (*state_tree->root(), Stateful::loading_state_version);
787 Session::load_state (string snapshot_name)
792 state_was_pending = false;
794 /* check for leftover pending state from a crashed capture attempt */
796 std::string xmlpath(_session_dir->root_path());
797 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
799 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
801 /* there is pending state from a crashed capture attempt */
803 boost::optional<int> r = AskAboutPendingState();
804 if (r.get_value_or (1)) {
805 state_was_pending = true;
809 if (!state_was_pending) {
810 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
813 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
814 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
815 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
816 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
821 state_tree = new XMLTree;
825 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
827 if (!state_tree->read (xmlpath)) {
828 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
834 XMLNode& root (*state_tree->root());
836 if (root.name() != X_("Session")) {
837 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
843 const XMLProperty* prop;
845 if ((prop = root.property ("version")) == 0) {
846 /* no version implies very old version of Ardour */
847 Stateful::loading_state_version = 1000;
849 if (prop->value().find ('.') != string::npos) {
850 /* old school version format */
851 if (prop->value()[0] == '2') {
852 Stateful::loading_state_version = 2000;
854 Stateful::loading_state_version = 3000;
857 Stateful::loading_state_version = atoi (prop->value());
861 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
863 std::string backup_path(_session_dir->root_path());
864 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
865 backup_path = Glib::build_filename (backup_path, backup_filename);
867 // only create a backup for a given statefile version once
869 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
871 VersionMismatch (xmlpath, backup_path);
873 if (!copy_file (xmlpath, backup_path)) {;
883 Session::load_options (const XMLNode& node)
885 LocaleGuard lg (X_("C"));
886 config.set_variables (node);
891 Session::save_default_options ()
893 return config.save_state();
903 Session::get_template()
905 /* if we don't disable rec-enable, diskstreams
906 will believe they need to store their capture
907 sources in their state node.
910 disable_record (false);
916 Session::state (bool full_state)
918 XMLNode* node = new XMLNode("Session");
922 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
923 node->add_property("version", buf);
925 /* store configuration settings */
929 node->add_property ("name", _name);
930 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
931 node->add_property ("sample-rate", buf);
933 if (session_dirs.size() > 1) {
937 vector<space_and_path>::iterator i = session_dirs.begin();
938 vector<space_and_path>::iterator next;
940 ++i; /* skip the first one */
944 while (i != session_dirs.end()) {
948 if (next != session_dirs.end()) {
949 p += G_SEARCHPATH_SEPARATOR;
958 child = node->add_child ("Path");
959 child->add_content (p);
963 /* save the ID counter */
965 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
966 node->add_property ("id-counter", buf);
968 /* save the event ID counter */
970 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
971 node->add_property ("event-counter", buf);
973 /* various options */
975 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
976 if (!midi_port_nodes.empty()) {
977 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
978 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
979 midi_port_stuff->add_child_nocopy (**n);
981 node->add_child_nocopy (*midi_port_stuff);
984 node->add_child_nocopy (config.get_variables ());
986 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
988 child = node->add_child ("Sources");
991 Glib::Threads::Mutex::Lock sl (source_lock);
993 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
995 /* Don't save information about non-file Sources, or
996 * about non-destructive file sources that are empty
997 * and unused by any regions.
1000 boost::shared_ptr<FileSource> fs;
1002 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1004 if (!fs->destructive()) {
1005 if (fs->empty() && !fs->used()) {
1010 child->add_child_nocopy (siter->second->get_state());
1015 child = node->add_child ("Regions");
1018 Glib::Threads::Mutex::Lock rl (region_lock);
1019 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1020 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1021 boost::shared_ptr<Region> r = i->second;
1022 /* only store regions not attached to playlists */
1023 if (r->playlist() == 0) {
1024 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1025 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1027 child->add_child_nocopy (r->get_state ());
1032 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1034 if (!cassocs.empty()) {
1035 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1037 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1039 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1040 i->first->id().print (buf, sizeof (buf));
1041 can->add_property (X_("copy"), buf);
1042 i->second->id().print (buf, sizeof (buf));
1043 can->add_property (X_("original"), buf);
1044 ca->add_child_nocopy (*can);
1054 node->add_child_nocopy (_locations->get_state());
1057 Locations loc (*this);
1058 // for a template, just create a new Locations, populate it
1059 // with the default start and end, and get the state for that.
1060 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1061 range->set (max_framepos, 0);
1063 XMLNode& locations_state = loc.get_state();
1065 if (ARDOUR::Profile->get_trx() && _locations) {
1066 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1067 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1068 locations_state.add_child_nocopy ((*i)->get_state ());
1072 node->add_child_nocopy (locations_state);
1075 child = node->add_child ("Bundles");
1077 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1078 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1079 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1081 child->add_child_nocopy (b->get_state());
1086 child = node->add_child ("Routes");
1088 boost::shared_ptr<RouteList> r = routes.reader ();
1090 RoutePublicOrderSorter cmp;
1091 RouteList public_order (*r);
1092 public_order.sort (cmp);
1094 /* the sort should have put control outs first */
1097 assert (_monitor_out == public_order.front());
1100 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1101 if (!(*i)->is_auditioner()) {
1103 child->add_child_nocopy ((*i)->get_state());
1105 child->add_child_nocopy ((*i)->get_template());
1111 playlists->add_state (node, full_state);
1113 child = node->add_child ("RouteGroups");
1114 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1115 child->add_child_nocopy ((*i)->get_state());
1119 XMLNode* gain_child = node->add_child ("Click");
1120 gain_child->add_child_nocopy (_click_io->state (full_state));
1121 gain_child->add_child_nocopy (_click_gain->state (full_state));
1125 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1126 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1130 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1131 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1134 node->add_child_nocopy (_speakers->get_state());
1135 node->add_child_nocopy (_tempo_map->get_state());
1136 node->add_child_nocopy (get_control_protocol_state());
1139 node->add_child_copy (*_extra_xml);
1146 Session::get_control_protocol_state ()
1148 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1149 return cpm.get_state();
1153 Session::set_state (const XMLNode& node, int version)
1157 const XMLProperty* prop;
1160 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1162 if (node.name() != X_("Session")) {
1163 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1167 if ((prop = node.property ("name")) != 0) {
1168 _name = prop->value ();
1171 if ((prop = node.property (X_("sample-rate"))) != 0) {
1173 _nominal_frame_rate = atoi (prop->value());
1175 if (_nominal_frame_rate != _current_frame_rate) {
1176 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1177 if (r.get_value_or (0)) {
1183 setup_raid_path(_session_dir->root_path());
1185 if ((prop = node.property (X_("id-counter"))) != 0) {
1187 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1188 ID::init_counter (x);
1190 /* old sessions used a timebased counter, so fake
1191 the startup ID counter based on a standard
1196 ID::init_counter (now);
1199 if ((prop = node.property (X_("event-counter"))) != 0) {
1200 Evoral::init_event_id_counter (atoi (prop->value()));
1204 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1205 _midi_ports->set_midi_port_states (child->children());
1208 IO::disable_connecting ();
1210 Stateful::save_extra_xml (node);
1212 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1213 load_options (*child);
1214 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1215 load_options (*child);
1217 error << _("Session: XML state has no options section") << endmsg;
1220 if (version >= 3000) {
1221 if ((child = find_named_node (node, "Metadata")) == 0) {
1222 warning << _("Session: XML state has no metadata section") << endmsg;
1223 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1228 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1229 _speakers->set_state (*child, version);
1232 if ((child = find_named_node (node, "Sources")) == 0) {
1233 error << _("Session: XML state has no sources section") << endmsg;
1235 } else if (load_sources (*child)) {
1239 if ((child = find_named_node (node, "TempoMap")) == 0) {
1240 error << _("Session: XML state has no Tempo Map section") << endmsg;
1242 } else if (_tempo_map->set_state (*child, version)) {
1246 if ((child = find_named_node (node, "Locations")) == 0) {
1247 error << _("Session: XML state has no locations section") << endmsg;
1249 } else if (_locations->set_state (*child, version)) {
1253 locations_changed ();
1255 if (_session_range_location) {
1256 AudioFileSource::set_header_position_offset (_session_range_location->start());
1259 if ((child = find_named_node (node, "Regions")) == 0) {
1260 error << _("Session: XML state has no Regions section") << endmsg;
1262 } else if (load_regions (*child)) {
1266 if ((child = find_named_node (node, "Playlists")) == 0) {
1267 error << _("Session: XML state has no playlists section") << endmsg;
1269 } else if (playlists->load (*this, *child)) {
1273 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1275 } else if (playlists->load_unused (*this, *child)) {
1279 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1280 if (load_compounds (*child)) {
1285 if (version >= 3000) {
1286 if ((child = find_named_node (node, "Bundles")) == 0) {
1287 warning << _("Session: XML state has no bundles section") << endmsg;
1290 /* We can't load Bundles yet as they need to be able
1291 to convert from port names to Port objects, which can't happen until
1293 _bundle_xml_node = new XMLNode (*child);
1297 if (version < 3000) {
1298 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1299 error << _("Session: XML state has no diskstreams section") << endmsg;
1301 } else if (load_diskstreams_2X (*child, version)) {
1306 if ((child = find_named_node (node, "Routes")) == 0) {
1307 error << _("Session: XML state has no routes section") << endmsg;
1309 } else if (load_routes (*child, version)) {
1313 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1314 _diskstreams_2X.clear ();
1316 if (version >= 3000) {
1318 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1319 error << _("Session: XML state has no route groups section") << endmsg;
1321 } else if (load_route_groups (*child, version)) {
1325 } else if (version < 3000) {
1327 if ((child = find_named_node (node, "EditGroups")) == 0) {
1328 error << _("Session: XML state has no edit groups section") << endmsg;
1330 } else if (load_route_groups (*child, version)) {
1334 if ((child = find_named_node (node, "MixGroups")) == 0) {
1335 error << _("Session: XML state has no mix groups section") << endmsg;
1337 } else if (load_route_groups (*child, version)) {
1342 if ((child = find_named_node (node, "Click")) == 0) {
1343 warning << _("Session: XML state has no click section") << endmsg;
1344 } else if (_click_io) {
1345 setup_click_state (&node);
1348 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1349 ControlProtocolManager::instance().set_state (*child, version);
1352 update_have_rec_enabled_track ();
1354 /* here beginneth the second phase ... */
1356 StateReady (); /* EMIT SIGNAL */
1369 Session::load_routes (const XMLNode& node, int version)
1372 XMLNodeConstIterator niter;
1373 RouteList new_routes;
1375 nlist = node.children();
1379 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1381 boost::shared_ptr<Route> route;
1382 if (version < 3000) {
1383 route = XMLRouteFactory_2X (**niter, version);
1385 route = XMLRouteFactory (**niter, version);
1389 error << _("Session: cannot create Route from XML description.") << endmsg;
1393 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1395 new_routes.push_back (route);
1398 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1400 add_routes (new_routes, false, false, false);
1402 BootMessage (_("Finished adding tracks/busses"));
1407 boost::shared_ptr<Route>
1408 Session::XMLRouteFactory (const XMLNode& node, int version)
1410 boost::shared_ptr<Route> ret;
1412 if (node.name() != "Route") {
1416 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1418 DataType type = DataType::AUDIO;
1419 const XMLProperty* prop = node.property("default-type");
1422 type = DataType (prop->value());
1425 assert (type != DataType::NIL);
1429 boost::shared_ptr<Track> track;
1431 if (type == DataType::AUDIO) {
1432 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1434 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1437 if (track->init()) {
1441 if (track->set_state (node, version)) {
1445 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1446 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1451 enum Route::Flag flags = Route::Flag(0);
1452 const XMLProperty* prop = node.property("flags");
1454 flags = Route::Flag (string_2_enum (prop->value(), flags));
1457 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1459 if (r->init () == 0 && r->set_state (node, version) == 0) {
1460 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1461 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1470 boost::shared_ptr<Route>
1471 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1473 boost::shared_ptr<Route> ret;
1475 if (node.name() != "Route") {
1479 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1481 ds_prop = node.property (X_("diskstream"));
1484 DataType type = DataType::AUDIO;
1485 const XMLProperty* prop = node.property("default-type");
1488 type = DataType (prop->value());
1491 assert (type != DataType::NIL);
1495 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1496 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1500 if (i == _diskstreams_2X.end()) {
1501 error << _("Could not find diskstream for route") << endmsg;
1502 return boost::shared_ptr<Route> ();
1505 boost::shared_ptr<Track> track;
1507 if (type == DataType::AUDIO) {
1508 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1510 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1513 if (track->init()) {
1517 if (track->set_state (node, version)) {
1521 track->set_diskstream (*i);
1523 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1524 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1529 enum Route::Flag flags = Route::Flag(0);
1530 const XMLProperty* prop = node.property("flags");
1532 flags = Route::Flag (string_2_enum (prop->value(), flags));
1535 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1537 if (r->init () == 0 && r->set_state (node, version) == 0) {
1538 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1539 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1549 Session::load_regions (const XMLNode& node)
1552 XMLNodeConstIterator niter;
1553 boost::shared_ptr<Region> region;
1555 nlist = node.children();
1559 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1560 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1561 error << _("Session: cannot create Region from XML description.");
1562 const XMLProperty *name = (**niter).property("name");
1565 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1576 Session::load_compounds (const XMLNode& node)
1578 XMLNodeList calist = node.children();
1579 XMLNodeConstIterator caiter;
1580 XMLProperty *caprop;
1582 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1583 XMLNode* ca = *caiter;
1587 if ((caprop = ca->property (X_("original"))) == 0) {
1590 orig_id = caprop->value();
1592 if ((caprop = ca->property (X_("copy"))) == 0) {
1595 copy_id = caprop->value();
1597 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1598 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1600 if (!orig || !copy) {
1601 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1607 RegionFactory::add_compound_association (orig, copy);
1614 Session::load_nested_sources (const XMLNode& node)
1617 XMLNodeConstIterator niter;
1619 nlist = node.children();
1621 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1622 if ((*niter)->name() == "Source") {
1624 /* it may already exist, so don't recreate it unnecessarily
1627 XMLProperty* prop = (*niter)->property (X_("id"));
1629 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1633 ID source_id (prop->value());
1635 if (!source_by_id (source_id)) {
1638 SourceFactory::create (*this, **niter, true);
1640 catch (failed_constructor& err) {
1641 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1648 boost::shared_ptr<Region>
1649 Session::XMLRegionFactory (const XMLNode& node, bool full)
1651 const XMLProperty* type = node.property("type");
1655 const XMLNodeList& nlist = node.children();
1657 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1658 XMLNode *child = (*niter);
1659 if (child->name() == "NestedSource") {
1660 load_nested_sources (*child);
1664 if (!type || type->value() == "audio") {
1665 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1666 } else if (type->value() == "midi") {
1667 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1670 } catch (failed_constructor& err) {
1671 return boost::shared_ptr<Region> ();
1674 return boost::shared_ptr<Region> ();
1677 boost::shared_ptr<AudioRegion>
1678 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1680 const XMLProperty* prop;
1681 boost::shared_ptr<Source> source;
1682 boost::shared_ptr<AudioSource> as;
1684 SourceList master_sources;
1685 uint32_t nchans = 1;
1688 if (node.name() != X_("Region")) {
1689 return boost::shared_ptr<AudioRegion>();
1692 if ((prop = node.property (X_("channels"))) != 0) {
1693 nchans = atoi (prop->value().c_str());
1696 if ((prop = node.property ("name")) == 0) {
1697 cerr << "no name for this region\n";
1701 if ((prop = node.property (X_("source-0"))) == 0) {
1702 if ((prop = node.property ("source")) == 0) {
1703 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1704 return boost::shared_ptr<AudioRegion>();
1708 PBD::ID s_id (prop->value());
1710 if ((source = source_by_id (s_id)) == 0) {
1711 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1712 return boost::shared_ptr<AudioRegion>();
1715 as = boost::dynamic_pointer_cast<AudioSource>(source);
1717 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1718 return boost::shared_ptr<AudioRegion>();
1721 sources.push_back (as);
1723 /* pickup other channels */
1725 for (uint32_t n=1; n < nchans; ++n) {
1726 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1727 if ((prop = node.property (buf)) != 0) {
1729 PBD::ID id2 (prop->value());
1731 if ((source = source_by_id (id2)) == 0) {
1732 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1733 return boost::shared_ptr<AudioRegion>();
1736 as = boost::dynamic_pointer_cast<AudioSource>(source);
1738 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1739 return boost::shared_ptr<AudioRegion>();
1741 sources.push_back (as);
1745 for (uint32_t n = 0; n < nchans; ++n) {
1746 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1747 if ((prop = node.property (buf)) != 0) {
1749 PBD::ID id2 (prop->value());
1751 if ((source = source_by_id (id2)) == 0) {
1752 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1753 return boost::shared_ptr<AudioRegion>();
1756 as = boost::dynamic_pointer_cast<AudioSource>(source);
1758 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1759 return boost::shared_ptr<AudioRegion>();
1761 master_sources.push_back (as);
1766 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1768 /* a final detail: this is the one and only place that we know how long missing files are */
1770 if (region->whole_file()) {
1771 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1772 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1774 sfp->set_length (region->length());
1779 if (!master_sources.empty()) {
1780 if (master_sources.size() != nchans) {
1781 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1783 region->set_master_sources (master_sources);
1791 catch (failed_constructor& err) {
1792 return boost::shared_ptr<AudioRegion>();
1796 boost::shared_ptr<MidiRegion>
1797 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1799 const XMLProperty* prop;
1800 boost::shared_ptr<Source> source;
1801 boost::shared_ptr<MidiSource> ms;
1804 if (node.name() != X_("Region")) {
1805 return boost::shared_ptr<MidiRegion>();
1808 if ((prop = node.property ("name")) == 0) {
1809 cerr << "no name for this region\n";
1813 if ((prop = node.property (X_("source-0"))) == 0) {
1814 if ((prop = node.property ("source")) == 0) {
1815 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1816 return boost::shared_ptr<MidiRegion>();
1820 PBD::ID s_id (prop->value());
1822 if ((source = source_by_id (s_id)) == 0) {
1823 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1824 return boost::shared_ptr<MidiRegion>();
1827 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1829 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1830 return boost::shared_ptr<MidiRegion>();
1833 sources.push_back (ms);
1836 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1837 /* a final detail: this is the one and only place that we know how long missing files are */
1839 if (region->whole_file()) {
1840 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1841 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1843 sfp->set_length (region->length());
1851 catch (failed_constructor& err) {
1852 return boost::shared_ptr<MidiRegion>();
1857 Session::get_sources_as_xml ()
1860 XMLNode* node = new XMLNode (X_("Sources"));
1861 Glib::Threads::Mutex::Lock lm (source_lock);
1863 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1864 node->add_child_nocopy (i->second->get_state());
1871 Session::reset_write_sources (bool mark_write_complete, bool force)
1873 boost::shared_ptr<RouteList> rl = routes.reader();
1874 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1875 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1878 // block state saving
1879 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1880 tr->reset_write_sources(mark_write_complete, force);
1881 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1887 Session::load_sources (const XMLNode& node)
1890 XMLNodeConstIterator niter;
1891 boost::shared_ptr<Source> source; /* don't need this but it stops some
1892 * versions of gcc complaining about
1893 * discarded return values.
1896 nlist = node.children();
1900 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1903 if ((source = XMLSourceFactory (**niter)) == 0) {
1904 error << _("Session: cannot create Source from XML description.") << endmsg;
1907 } catch (MissingSource& err) {
1911 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1912 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1913 PROGRAM_NAME) << endmsg;
1917 if (!no_questions_about_missing_files) {
1918 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1923 switch (user_choice) {
1925 /* user added a new search location, so try again */
1930 /* user asked to quit the entire session load
1935 no_questions_about_missing_files = true;
1939 no_questions_about_missing_files = true;
1946 case DataType::AUDIO:
1947 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1950 case DataType::MIDI:
1951 /* The MIDI file is actually missing so
1952 * just create a new one in the same
1953 * location. Do not announce its
1957 if (!Glib::path_is_absolute (err.path)) {
1958 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
1960 /* this should be an unrecoverable error: we would be creating a MIDI file outside
1965 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
1966 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
1967 /* reset ID to match the missing one */
1968 source->set_id (**niter);
1969 /* Now we can announce it */
1970 SourceFactory::SourceCreated (source);
1981 boost::shared_ptr<Source>
1982 Session::XMLSourceFactory (const XMLNode& node)
1984 if (node.name() != "Source") {
1985 return boost::shared_ptr<Source>();
1989 /* note: do peak building in another thread when loading session state */
1990 return SourceFactory::create (*this, node, true);
1993 catch (failed_constructor& err) {
1994 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
1995 return boost::shared_ptr<Source>();
2000 Session::save_template (string template_name)
2002 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2006 bool absolute_path = Glib::path_is_absolute (template_name);
2008 /* directory to put the template in */
2009 std::string template_dir_path;
2011 if (!absolute_path) {
2012 std::string user_template_dir(user_template_directory());
2014 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2015 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2016 user_template_dir, g_strerror (errno)) << endmsg;
2020 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2022 template_dir_path = template_name;
2025 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2026 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2027 template_dir_path) << endmsg;
2031 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2032 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2033 template_dir_path, g_strerror (errno)) << endmsg;
2038 std::string template_file_path;
2039 if (absolute_path) {
2040 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2042 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2045 SessionSaveUnderway (); /* EMIT SIGNAL */
2049 tree.set_root (&get_template());
2050 if (!tree.write (template_file_path)) {
2051 error << _("template not saved") << endmsg;
2055 if (!ARDOUR::Profile->get_trx()) {
2056 /* copy plugin state directory */
2058 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2060 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2061 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2062 template_plugin_state_path, g_strerror (errno)) << endmsg;
2065 copy_files (plugins_dir(), template_plugin_state_path);
2072 Session::refresh_disk_space ()
2074 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2076 Glib::Threads::Mutex::Lock lm (space_lock);
2078 /* get freespace on every FS that is part of the session path */
2080 _total_free_4k_blocks = 0;
2081 _total_free_4k_blocks_uncertain = false;
2083 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2085 struct statfs statfsbuf;
2086 statfs (i->path.c_str(), &statfsbuf);
2088 double const scale = statfsbuf.f_bsize / 4096.0;
2090 /* See if this filesystem is read-only */
2091 struct statvfs statvfsbuf;
2092 statvfs (i->path.c_str(), &statvfsbuf);
2094 /* f_bavail can be 0 if it is undefined for whatever
2095 filesystem we are looking at; Samba shares mounted
2096 via GVFS are an example of this.
2098 if (statfsbuf.f_bavail == 0) {
2099 /* block count unknown */
2101 i->blocks_unknown = true;
2102 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2103 /* read-only filesystem */
2105 i->blocks_unknown = false;
2107 /* read/write filesystem with known space */
2108 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2109 i->blocks_unknown = false;
2112 _total_free_4k_blocks += i->blocks;
2113 if (i->blocks_unknown) {
2114 _total_free_4k_blocks_uncertain = true;
2117 #elif defined PLATFORM_WINDOWS
2118 vector<string> scanned_volumes;
2119 vector<string>::iterator j;
2120 vector<space_and_path>::iterator i;
2121 DWORD nSectorsPerCluster, nBytesPerSector,
2122 nFreeClusters, nTotalClusters;
2126 _total_free_4k_blocks = 0;
2128 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2129 strncpy (disk_drive, (*i).path.c_str(), 3);
2133 volume_found = false;
2134 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2136 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2137 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2138 i->blocks = (uint32_t)(nFreeBytes / 4096);
2140 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2141 if (0 == j->compare(disk_drive)) {
2142 volume_found = true;
2147 if (!volume_found) {
2148 scanned_volumes.push_back(disk_drive);
2149 _total_free_4k_blocks += i->blocks;
2154 if (0 == _total_free_4k_blocks) {
2155 strncpy (disk_drive, path().c_str(), 3);
2158 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2160 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2161 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2162 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2169 Session::get_best_session_directory_for_new_audio ()
2171 vector<space_and_path>::iterator i;
2172 string result = _session_dir->root_path();
2174 /* handle common case without system calls */
2176 if (session_dirs.size() == 1) {
2180 /* OK, here's the algorithm we're following here:
2182 We want to select which directory to use for
2183 the next file source to be created. Ideally,
2184 we'd like to use a round-robin process so as to
2185 get maximum performance benefits from splitting
2186 the files across multiple disks.
2188 However, in situations without much diskspace, an
2189 RR approach may end up filling up a filesystem
2190 with new files while others still have space.
2191 Its therefore important to pay some attention to
2192 the freespace in the filesystem holding each
2193 directory as well. However, if we did that by
2194 itself, we'd keep creating new files in the file
2195 system with the most space until it was as full
2196 as all others, thus negating any performance
2197 benefits of this RAID-1 like approach.
2199 So, we use a user-configurable space threshold. If
2200 there are at least 2 filesystems with more than this
2201 much space available, we use RR selection between them.
2202 If not, then we pick the filesystem with the most space.
2204 This gets a good balance between the two
2208 refresh_disk_space ();
2210 int free_enough = 0;
2212 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2213 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2218 if (free_enough >= 2) {
2219 /* use RR selection process, ensuring that the one
2223 i = last_rr_session_dir;
2226 if (++i == session_dirs.end()) {
2227 i = session_dirs.begin();
2230 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2231 SessionDirectory sdir(i->path);
2232 if (sdir.create ()) {
2234 last_rr_session_dir = i;
2239 } while (i != last_rr_session_dir);
2243 /* pick FS with the most freespace (and that
2244 seems to actually work ...)
2247 vector<space_and_path> sorted;
2248 space_and_path_ascending_cmp cmp;
2250 sorted = session_dirs;
2251 sort (sorted.begin(), sorted.end(), cmp);
2253 for (i = sorted.begin(); i != sorted.end(); ++i) {
2254 SessionDirectory sdir(i->path);
2255 if (sdir.create ()) {
2257 last_rr_session_dir = i;
2267 Session::automation_dir () const
2269 return Glib::build_filename (_path, "automation");
2273 Session::analysis_dir () const
2275 return Glib::build_filename (_path, "analysis");
2279 Session::plugins_dir () const
2281 return Glib::build_filename (_path, "plugins");
2285 Session::externals_dir () const
2287 return Glib::build_filename (_path, "externals");
2291 Session::load_bundles (XMLNode const & node)
2293 XMLNodeList nlist = node.children();
2294 XMLNodeConstIterator niter;
2298 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2299 if ((*niter)->name() == "InputBundle") {
2300 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2301 } else if ((*niter)->name() == "OutputBundle") {
2302 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2304 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2313 Session::load_route_groups (const XMLNode& node, int version)
2315 XMLNodeList nlist = node.children();
2316 XMLNodeConstIterator niter;
2320 if (version >= 3000) {
2322 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2323 if ((*niter)->name() == "RouteGroup") {
2324 RouteGroup* rg = new RouteGroup (*this, "");
2325 add_route_group (rg);
2326 rg->set_state (**niter, version);
2330 } else if (version < 3000) {
2332 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2333 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2334 RouteGroup* rg = new RouteGroup (*this, "");
2335 add_route_group (rg);
2336 rg->set_state (**niter, version);
2345 state_file_filter (const string &str, void* /*arg*/)
2347 return (str.length() > strlen(statefile_suffix) &&
2348 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2352 remove_end(string state)
2354 string statename(state);
2356 string::size_type start,end;
2357 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2358 statename = statename.substr (start+1);
2361 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2362 end = statename.length();
2365 return string(statename.substr (0, end));
2369 Session::possible_states (string path)
2371 vector<string> states;
2372 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2374 transform(states.begin(), states.end(), states.begin(), remove_end);
2376 sort (states.begin(), states.end());
2382 Session::possible_states () const
2384 return possible_states(_path);
2388 Session::add_route_group (RouteGroup* g)
2390 _route_groups.push_back (g);
2391 route_group_added (g); /* EMIT SIGNAL */
2393 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2394 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2395 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2401 Session::remove_route_group (RouteGroup& rg)
2403 list<RouteGroup*>::iterator i;
2405 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2406 _route_groups.erase (i);
2409 route_group_removed (); /* EMIT SIGNAL */
2413 /** Set a new order for our route groups, without adding or removing any.
2414 * @param groups Route group list in the new order.
2417 Session::reorder_route_groups (list<RouteGroup*> groups)
2419 _route_groups = groups;
2421 route_groups_reordered (); /* EMIT SIGNAL */
2427 Session::route_group_by_name (string name)
2429 list<RouteGroup *>::iterator i;
2431 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2432 if ((*i)->name() == name) {
2440 Session::all_route_group() const
2442 return *_all_route_group;
2446 Session::add_commands (vector<Command*> const & cmds)
2448 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2454 Session::begin_reversible_command (const string& name)
2456 begin_reversible_command (g_quark_from_string (name.c_str ()));
2459 /** Begin a reversible command using a GQuark to identify it.
2460 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2461 * but there must be as many begin...()s as there are commit...()s.
2464 Session::begin_reversible_command (GQuark q)
2466 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2467 to hold all the commands that are committed. This keeps the order of
2468 commands correct in the history.
2471 if (_current_trans == 0) {
2472 /* start a new transaction */
2473 assert (_current_trans_quarks.empty ());
2474 _current_trans = new UndoTransaction();
2475 _current_trans->set_name (g_quark_to_string (q));
2478 _current_trans_quarks.push_front (q);
2482 Session::abort_reversible_command ()
2484 if (_current_trans != 0) {
2485 _current_trans->clear();
2486 delete _current_trans;
2488 _current_trans_quarks.clear();
2493 Session::commit_reversible_command (Command *cmd)
2495 assert (_current_trans);
2496 assert (!_current_trans_quarks.empty ());
2501 _current_trans->add_command (cmd);
2504 _current_trans_quarks.pop_front ();
2506 if (!_current_trans_quarks.empty ()) {
2507 /* the transaction we're committing is not the top-level one */
2511 if (_current_trans->empty()) {
2512 /* no commands were added to the transaction, so just get rid of it */
2513 delete _current_trans;
2518 gettimeofday (&now, 0);
2519 _current_trans->set_timestamp (now);
2521 _history.add (_current_trans);
2526 accept_all_audio_files (const string& path, void* /*arg*/)
2528 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2532 if (!AudioFileSource::safe_audio_file_extension (path)) {
2540 accept_all_midi_files (const string& path, void* /*arg*/)
2542 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2546 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2547 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2548 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2552 accept_all_state_files (const string& path, void* /*arg*/)
2554 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2558 std::string const statefile_ext (statefile_suffix);
2559 if (path.length() >= statefile_ext.length()) {
2560 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2567 Session::find_all_sources (string path, set<string>& result)
2572 if (!tree.read (path)) {
2576 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2581 XMLNodeConstIterator niter;
2583 nlist = node->children();
2587 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2591 if ((prop = (*niter)->property (X_("type"))) == 0) {
2595 DataType type (prop->value());
2597 if ((prop = (*niter)->property (X_("name"))) == 0) {
2601 if (Glib::path_is_absolute (prop->value())) {
2602 /* external file, ignore */
2610 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2611 result.insert (found_path);
2619 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2621 vector<string> state_files;
2623 string this_snapshot_path;
2629 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2630 ripped = ripped.substr (0, ripped.length() - 1);
2633 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2635 if (state_files.empty()) {
2640 this_snapshot_path = _path;
2641 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2642 this_snapshot_path += statefile_suffix;
2644 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2646 if (exclude_this_snapshot && *i == this_snapshot_path) {
2650 if (find_all_sources (*i, result) < 0) {
2658 struct RegionCounter {
2659 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2660 AudioSourceList::iterator iter;
2661 boost::shared_ptr<Region> region;
2664 RegionCounter() : count (0) {}
2668 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2670 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2671 return r.get_value_or (1);
2675 Session::cleanup_regions ()
2677 bool removed = false;
2678 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2680 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2682 uint32_t used = playlists->region_use_count (i->second);
2684 if (used == 0 && !i->second->automatic ()) {
2686 RegionFactory::map_remove (i->second);
2691 // re-check to remove parent references of compound regions
2692 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2693 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2696 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2697 if (0 == playlists->region_use_count (i->second)) {
2698 RegionFactory::map_remove (i->second);
2703 /* dump the history list */
2710 Session::cleanup_sources (CleanupReport& rep)
2712 // FIXME: needs adaptation to midi
2714 vector<boost::shared_ptr<Source> > dead_sources;
2717 vector<string> candidates;
2718 vector<string> unused;
2719 set<string> all_sources;
2728 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2730 /* consider deleting all unused playlists */
2732 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2737 /* sync the "all regions" property of each playlist with its current state
2740 playlists->sync_all_regions_with_regions ();
2742 /* find all un-used sources */
2747 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2749 SourceMap::iterator tmp;
2754 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2758 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2759 dead_sources.push_back (i->second);
2760 i->second->drop_references ();
2766 /* build a list of all the possible audio directories for the session */
2768 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2769 SessionDirectory sdir ((*i).path);
2770 asp += sdir.sound_path();
2772 audio_path += asp.to_string();
2775 /* build a list of all the possible midi directories for the session */
2777 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2778 SessionDirectory sdir ((*i).path);
2779 msp += sdir.midi_path();
2781 midi_path += msp.to_string();
2783 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2784 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2786 /* find all sources, but don't use this snapshot because the
2787 state file on disk still references sources we may have already
2791 find_all_sources_across_snapshots (all_sources, true);
2793 /* add our current source list
2796 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2797 boost::shared_ptr<FileSource> fs;
2798 SourceMap::iterator tmp = i;
2801 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2803 if (!fs->is_stub()) {
2805 if (playlists->source_use_count (fs) != 0) {
2806 all_sources.insert (fs->path());
2809 /* we might not remove this source from disk, because it may be used
2810 by other snapshots, but its not being used in this version
2811 so lets get rid of it now, along with any representative regions
2815 RegionFactory::remove_regions_using_source (i->second);
2818 // also remove source from all_sources
2820 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2821 spath = Glib::path_get_basename (*j);
2822 if ( spath == i->second->name () ) {
2823 all_sources.erase (j);
2834 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2839 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2841 tmppath1 = canonical_path (spath);
2842 tmppath2 = canonical_path ((*i));
2844 if (tmppath1 == tmppath2) {
2851 unused.push_back (spath);
2855 /* now try to move all unused files into the "dead" directory(ies) */
2857 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2858 struct stat statbuf;
2862 /* don't move the file across filesystems, just
2863 stick it in the `dead_dir_name' directory
2864 on whichever filesystem it was already on.
2867 if ((*x).find ("/sounds/") != string::npos) {
2869 /* old school, go up 1 level */
2871 newpath = Glib::path_get_dirname (*x); // "sounds"
2872 newpath = Glib::path_get_dirname (newpath); // "session-name"
2876 /* new school, go up 4 levels */
2878 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2879 newpath = Glib::path_get_dirname (newpath); // "session-name"
2880 newpath = Glib::path_get_dirname (newpath); // "interchange"
2881 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2884 newpath = Glib::build_filename (newpath, dead_dir_name);
2886 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2887 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2891 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2893 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2895 /* the new path already exists, try versioning */
2897 char buf[PATH_MAX+1];
2901 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2904 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2905 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2909 if (version == 999) {
2910 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2914 newpath = newpath_v;
2919 /* it doesn't exist, or we can't read it or something */
2923 stat ((*x).c_str(), &statbuf);
2925 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2926 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2927 (*x), newpath, strerror (errno))
2932 /* see if there an easy to find peakfile for this file, and remove it.
2935 string base = basename_nosuffix (*x);
2936 base += "%A"; /* this is what we add for the channel suffix of all native files,
2937 or for the first channel of embedded files. it will miss
2938 some peakfiles for other channels
2940 string peakpath = peak_path (base);
2942 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2943 if (::g_unlink (peakpath.c_str()) != 0) {
2944 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2945 peakpath, _path, strerror (errno))
2947 /* try to back out */
2948 ::rename (newpath.c_str(), _path.c_str());
2953 rep.paths.push_back (*x);
2954 rep.space += statbuf.st_size;
2957 /* dump the history list */
2961 /* save state so we don't end up a session file
2962 referring to non-existent sources.
2969 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2975 Session::cleanup_trash_sources (CleanupReport& rep)
2977 // FIXME: needs adaptation for MIDI
2979 vector<space_and_path>::iterator i;
2985 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2987 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2989 clear_directory (dead_dir, &rep.space, &rep.paths);
2996 Session::set_dirty ()
2998 /* never mark session dirty during loading */
3000 if (_state_of_the_state & Loading) {
3004 bool was_dirty = dirty();
3006 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3010 DirtyChanged(); /* EMIT SIGNAL */
3016 Session::set_clean ()
3018 bool was_dirty = dirty();
3020 _state_of_the_state = Clean;
3024 DirtyChanged(); /* EMIT SIGNAL */
3029 Session::set_deletion_in_progress ()
3031 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3035 Session::clear_deletion_in_progress ()
3037 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3041 Session::add_controllable (boost::shared_ptr<Controllable> c)
3043 /* this adds a controllable to the list managed by the Session.
3044 this is a subset of those managed by the Controllable class
3045 itself, and represents the only ones whose state will be saved
3046 as part of the session.
3049 Glib::Threads::Mutex::Lock lm (controllables_lock);
3050 controllables.insert (c);
3053 struct null_deleter { void operator()(void const *) const {} };
3056 Session::remove_controllable (Controllable* c)
3058 if (_state_of_the_state & Deletion) {
3062 Glib::Threads::Mutex::Lock lm (controllables_lock);
3064 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3066 if (x != controllables.end()) {
3067 controllables.erase (x);
3071 boost::shared_ptr<Controllable>
3072 Session::controllable_by_id (const PBD::ID& id)
3074 Glib::Threads::Mutex::Lock lm (controllables_lock);
3076 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3077 if ((*i)->id() == id) {
3082 return boost::shared_ptr<Controllable>();
3085 boost::shared_ptr<Controllable>
3086 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3088 boost::shared_ptr<Controllable> c;
3089 boost::shared_ptr<Route> r;
3091 switch (desc.top_level_type()) {
3092 case ControllableDescriptor::NamedRoute:
3094 std::string str = desc.top_level_name();
3095 if (str == "Master" || str == "master") {
3097 } else if (str == "control" || str == "listen") {
3100 r = route_by_name (desc.top_level_name());
3105 case ControllableDescriptor::RemoteControlID:
3106 r = route_by_remote_id (desc.rid());
3114 switch (desc.subtype()) {
3115 case ControllableDescriptor::Gain:
3116 c = r->gain_control ();
3119 case ControllableDescriptor::Trim:
3120 c = r->trim()->gain_control ();
3123 case ControllableDescriptor::Solo:
3124 c = r->solo_control();
3127 case ControllableDescriptor::Mute:
3128 c = r->mute_control();
3131 case ControllableDescriptor::Recenable:
3133 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3136 c = t->rec_enable_control ();
3141 case ControllableDescriptor::PanDirection:
3143 c = r->pannable()->pan_azimuth_control;
3147 case ControllableDescriptor::PanWidth:
3149 c = r->pannable()->pan_width_control;
3153 case ControllableDescriptor::PanElevation:
3155 c = r->pannable()->pan_elevation_control;
3159 case ControllableDescriptor::Balance:
3160 /* XXX simple pan control */
3163 case ControllableDescriptor::PluginParameter:
3165 uint32_t plugin = desc.target (0);
3166 uint32_t parameter_index = desc.target (1);
3168 /* revert to zero based counting */
3174 if (parameter_index > 0) {
3178 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3181 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3182 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3187 case ControllableDescriptor::SendGain:
3189 uint32_t send = desc.target (0);
3191 /* revert to zero-based counting */
3197 boost::shared_ptr<Processor> p = r->nth_send (send);
3200 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3201 boost::shared_ptr<Amp> a = s->amp();
3204 c = s->amp()->gain_control();
3211 /* relax and return a null pointer */
3219 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3222 Stateful::add_instant_xml (node, _path);
3225 if (write_to_config) {
3226 Config->add_instant_xml (node);
3231 Session::instant_xml (const string& node_name)
3233 return Stateful::instant_xml (node_name, _path);
3237 Session::save_history (string snapshot_name)
3245 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3246 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3250 if (snapshot_name.empty()) {
3251 snapshot_name = _current_snapshot_name;
3254 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3255 const string backup_filename = history_filename + backup_suffix;
3256 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3257 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3259 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3260 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3261 error << _("could not backup old history file, current history not saved") << endmsg;
3266 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3268 if (!tree.write (xml_path))
3270 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3272 if (g_remove (xml_path.c_str()) != 0) {
3273 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3274 xml_path, g_strerror (errno)) << endmsg;
3276 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3277 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3278 backup_path, g_strerror (errno)) << endmsg;
3288 Session::restore_history (string snapshot_name)
3292 if (snapshot_name.empty()) {
3293 snapshot_name = _current_snapshot_name;
3296 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3297 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3299 info << "Loading history from " << xml_path << endmsg;
3301 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3302 info << string_compose (_("%1: no history file \"%2\" for this session."),
3303 _name, xml_path) << endmsg;
3307 if (!tree.read (xml_path)) {
3308 error << string_compose (_("Could not understand session history file \"%1\""),
3309 xml_path) << endmsg;
3316 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3319 UndoTransaction* ut = new UndoTransaction ();
3322 ut->set_name(t->property("name")->value());
3323 stringstream ss(t->property("tv-sec")->value());
3325 ss.str(t->property("tv-usec")->value());
3327 ut->set_timestamp(tv);
3329 for (XMLNodeConstIterator child_it = t->children().begin();
3330 child_it != t->children().end(); child_it++)
3332 XMLNode *n = *child_it;
3335 if (n->name() == "MementoCommand" ||
3336 n->name() == "MementoUndoCommand" ||
3337 n->name() == "MementoRedoCommand") {
3339 if ((c = memento_command_factory(n))) {
3343 } else if (n->name() == "NoteDiffCommand") {
3344 PBD::ID id (n->property("midi-source")->value());
3345 boost::shared_ptr<MidiSource> midi_source =
3346 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3348 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3350 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3353 } else if (n->name() == "SysExDiffCommand") {
3355 PBD::ID id (n->property("midi-source")->value());
3356 boost::shared_ptr<MidiSource> midi_source =
3357 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3359 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3361 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3364 } else if (n->name() == "PatchChangeDiffCommand") {
3366 PBD::ID id (n->property("midi-source")->value());
3367 boost::shared_ptr<MidiSource> midi_source =
3368 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3370 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3372 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3375 } else if (n->name() == "StatefulDiffCommand") {
3376 if ((c = stateful_diff_command_factory (n))) {
3377 ut->add_command (c);
3380 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3391 Session::config_changed (std::string p, bool ours)
3397 if (p == "seamless-loop") {
3399 } else if (p == "rf-speed") {
3401 } else if (p == "auto-loop") {
3403 } else if (p == "auto-input") {
3405 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3406 /* auto-input only makes a difference if we're rolling */
3407 set_track_monitor_input_status (!config.get_auto_input());
3410 } else if (p == "punch-in") {
3414 if ((location = _locations->auto_punch_location()) != 0) {
3416 if (config.get_punch_in ()) {
3417 replace_event (SessionEvent::PunchIn, location->start());
3419 remove_event (location->start(), SessionEvent::PunchIn);
3423 } else if (p == "punch-out") {
3427 if ((location = _locations->auto_punch_location()) != 0) {
3429 if (config.get_punch_out()) {
3430 replace_event (SessionEvent::PunchOut, location->end());
3432 clear_events (SessionEvent::PunchOut);
3436 } else if (p == "edit-mode") {
3438 Glib::Threads::Mutex::Lock lm (playlists->lock);
3440 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3441 (*i)->set_edit_mode (Config->get_edit_mode ());
3444 } else if (p == "use-video-sync") {
3446 waiting_for_sync_offset = config.get_use_video_sync();
3448 } else if (p == "mmc-control") {
3450 //poke_midi_thread ();
3452 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3454 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3456 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3458 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3460 } else if (p == "midi-control") {
3462 //poke_midi_thread ();
3464 } else if (p == "raid-path") {
3466 setup_raid_path (config.get_raid_path());
3468 } else if (p == "timecode-format") {
3472 } else if (p == "video-pullup") {
3476 } else if (p == "seamless-loop") {
3478 if (play_loop && transport_rolling()) {
3479 // to reset diskstreams etc
3480 request_play_loop (true);
3483 } else if (p == "rf-speed") {
3485 cumulative_rf_motion = 0;
3488 } else if (p == "click-sound") {
3490 setup_click_sounds (1);
3492 } else if (p == "click-emphasis-sound") {
3494 setup_click_sounds (-1);
3496 } else if (p == "clicking") {
3498 if (Config->get_clicking()) {
3499 if (_click_io && click_data) { // don't require emphasis data
3506 } else if (p == "click-gain") {
3509 _click_gain->set_gain (Config->get_click_gain(), this);
3512 } else if (p == "send-mtc") {
3514 if (Config->get_send_mtc ()) {
3515 /* mark us ready to send */
3516 next_quarter_frame_to_send = 0;
3519 } else if (p == "send-mmc") {
3521 _mmc->enable_send (Config->get_send_mmc ());
3523 } else if (p == "midi-feedback") {
3525 session_midi_feedback = Config->get_midi_feedback();
3527 } else if (p == "jack-time-master") {
3529 engine().reset_timebase ();
3531 } else if (p == "native-file-header-format") {
3533 if (!first_file_header_format_reset) {
3534 reset_native_file_format ();
3537 first_file_header_format_reset = false;
3539 } else if (p == "native-file-data-format") {
3541 if (!first_file_data_format_reset) {
3542 reset_native_file_format ();
3545 first_file_data_format_reset = false;
3547 } else if (p == "external-sync") {
3548 if (!config.get_external_sync()) {
3549 drop_sync_source ();
3551 switch_to_sync_source (Config->get_sync_source());
3553 } else if (p == "denormal-model") {
3555 } else if (p == "history-depth") {
3556 set_history_depth (Config->get_history_depth());
3557 } else if (p == "remote-model") {
3558 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3561 } else if (p == "initial-program-change") {
3563 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3566 buf[0] = MIDI::program; // channel zero by default
3567 buf[1] = (Config->get_initial_program_change() & 0x7f);
3569 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3571 } else if (p == "solo-mute-override") {
3572 // catch_up_on_solo_mute_override ();
3573 } else if (p == "listen-position" || p == "pfl-position") {
3574 listen_position_changed ();
3575 } else if (p == "solo-control-is-listen-control") {
3576 solo_control_mode_changed ();
3577 } else if (p == "solo-mute-gain") {
3578 _solo_cut_control->Changed();
3579 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3580 last_timecode_valid = false;
3581 } else if (p == "playback-buffer-seconds") {
3582 AudioSource::allocate_working_buffers (frame_rate());
3583 } else if (p == "ltc-source-port") {
3584 reconnect_ltc_input ();
3585 } else if (p == "ltc-sink-port") {
3586 reconnect_ltc_output ();
3587 } else if (p == "timecode-generator-offset") {
3588 ltc_tx_parse_offset();
3595 Session::set_history_depth (uint32_t d)
3597 _history.set_depth (d);
3601 Session::load_diskstreams_2X (XMLNode const & node, int)
3604 XMLNodeConstIterator citer;
3606 clist = node.children();
3608 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3611 /* diskstreams added automatically by DiskstreamCreated handler */
3612 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3613 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3614 _diskstreams_2X.push_back (dsp);
3616 error << _("Session: unknown diskstream type in XML") << endmsg;
3620 catch (failed_constructor& err) {
3621 error << _("Session: could not load diskstream via XML state") << endmsg;
3629 /** Connect things to the MMC object */
3631 Session::setup_midi_machine_control ()
3633 _mmc = new MIDI::MachineControl;
3634 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3636 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3637 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3638 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3639 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3640 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3641 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3642 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3643 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3644 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3645 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3646 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3647 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3648 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3650 /* also handle MIDI SPP because its so common */
3652 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3653 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3654 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3657 boost::shared_ptr<Controllable>
3658 Session::solo_cut_control() const
3660 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3661 controls in Ardour that currently get presented to the user in the GUI that require
3662 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3664 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3665 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3669 return _solo_cut_control;
3673 Session::rename (const std::string& new_name)
3675 string legal_name = legalize_for_path (new_name);
3681 string const old_sources_root = _session_dir->sources_root();
3683 if (!_writable || (_state_of_the_state & CannotSave)) {
3684 error << _("Cannot rename read-only session.") << endmsg;
3685 return 0; // don't show "messed up" warning
3687 if (record_status() == Recording) {
3688 error << _("Cannot rename session while recording") << endmsg;
3689 return 0; // don't show "messed up" warning
3692 StateProtector stp (this);
3697 * interchange subdirectory
3701 * Backup files are left unchanged and not renamed.
3704 /* Windows requires that we close all files before attempting the
3705 * rename. This works on other platforms, but isn't necessary there.
3706 * Leave it in place for all platforms though, since it may help
3707 * catch issues that could arise if the way Source files work ever
3708 * change (since most developers are not using Windows).
3711 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3712 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3718 /* pass one: not 100% safe check that the new directory names don't
3722 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3726 /* this is a stupid hack because Glib::path_get_dirname() is
3727 * lexical-only, and so passing it /a/b/c/ gives a different
3728 * result than passing it /a/b/c ...
3731 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3732 oldstr = oldstr.substr (0, oldstr.length() - 1);
3735 string base = Glib::path_get_dirname (oldstr);
3737 newstr = Glib::build_filename (base, legal_name);
3739 cerr << "Looking for " << newstr << endl;
3741 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3742 cerr << " exists\n";
3751 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3757 /* this is a stupid hack because Glib::path_get_dirname() is
3758 * lexical-only, and so passing it /a/b/c/ gives a different
3759 * result than passing it /a/b/c ...
3762 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3763 oldstr = oldstr.substr (0, oldstr.length() - 1);
3766 string base = Glib::path_get_dirname (oldstr);
3767 newstr = Glib::build_filename (base, legal_name);
3769 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3771 cerr << "Rename " << oldstr << " => " << newstr << endl;
3772 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3773 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3774 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3778 /* Reset path in "session dirs" */
3783 /* reset primary SessionDirectory object */
3786 (*_session_dir) = newstr;
3791 /* now rename directory below session_dir/interchange */
3793 string old_interchange_dir;
3794 string new_interchange_dir;
3796 /* use newstr here because we renamed the path
3797 * (folder/directory) that used to be oldstr to newstr above
3800 v.push_back (newstr);
3801 v.push_back (interchange_dir_name);
3802 v.push_back (Glib::path_get_basename (oldstr));
3804 old_interchange_dir = Glib::build_filename (v);
3807 v.push_back (newstr);
3808 v.push_back (interchange_dir_name);
3809 v.push_back (legal_name);
3811 new_interchange_dir = Glib::build_filename (v);
3813 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3815 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3816 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3817 old_interchange_dir, new_interchange_dir,
3820 error << string_compose (_("renaming %s as %2 failed (%3)"),
3821 old_interchange_dir, new_interchange_dir,
3830 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3831 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3833 cerr << "Rename " << oldstr << " => " << newstr << endl;
3835 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3836 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3837 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3843 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3845 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3846 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3848 cerr << "Rename " << oldstr << " => " << newstr << endl;
3850 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3851 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3852 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3857 /* remove old name from recent sessions */
3858 remove_recent_sessions (_path);
3861 /* update file source paths */
3863 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3864 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3866 string p = fs->path ();
3867 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3869 SourceFactory::setup_peakfile(i->second, true);
3873 _current_snapshot_name = new_name;
3878 /* save state again to get everything just right */
3880 save_state (_current_snapshot_name);
3882 /* add to recent sessions */
3884 store_recent_sessions (new_name, _path);
3890 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3892 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3896 if (!tree.read (xmlpath)) {
3904 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3907 bool found_sr = false;
3908 bool found_data_format = false;
3910 if (get_session_info_from_path (tree, xmlpath)) {
3916 const XMLProperty* prop;
3917 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3918 sample_rate = atoi (prop->value());
3922 const XMLNodeList& children (tree.root()->children());
3923 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3924 const XMLNode* child = *c;
3925 if (child->name() == "Config") {
3926 const XMLNodeList& options (child->children());
3927 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3928 const XMLNode* option = *oc;
3929 const XMLProperty* name = option->property("name");
3935 if (name->value() == "native-file-data-format") {
3936 const XMLProperty* value = option->property ("value");
3938 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3940 found_data_format = true;
3946 if (found_data_format) {
3951 return !(found_sr && found_data_format); // zero if they are both found
3954 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
3955 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
3958 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
3962 SourcePathMap source_path_map;
3964 boost::shared_ptr<AudioFileSource> afs;
3969 Glib::Threads::Mutex::Lock lm (source_lock);
3971 cerr << " total sources = " << sources.size();
3973 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3974 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3980 if (fs->within_session()) {
3984 if (source_path_map.find (fs->path()) != source_path_map.end()) {
3985 source_path_map[fs->path()].push_back (fs);
3987 SeveralFileSources v;
3989 source_path_map.insert (make_pair (fs->path(), v));
3995 cerr << " fsources = " << total << endl;
3997 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
3999 /* tell caller where we are */
4001 string old_path = i->first;
4003 callback (n, total, old_path);
4005 cerr << old_path << endl;
4009 switch (i->second.front()->type()) {
4010 case DataType::AUDIO:
4011 new_path = new_audio_source_path_for_embedded (old_path);
4014 case DataType::MIDI:
4015 /* XXX not implemented yet */
4019 if (new_path.empty()) {
4023 cerr << "Move " << old_path << " => " << new_path << endl;
4025 if (!copy_file (old_path, new_path)) {
4026 cerr << "failed !\n";
4030 /* make sure we stop looking in the external
4031 dir/folder. Remember, this is an all-or-nothing
4032 operations, it doesn't merge just some files.
4034 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4036 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4037 (*f)->set_path (new_path);
4042 save_state ("", false, false);
4048 bool accept_all_files (string const &, void *)
4054 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4056 /* 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.
4061 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4063 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4065 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4067 v.push_back (new_session_folder); /* full path */
4068 v.push_back (interchange_dir_name);
4069 v.push_back (new_session_path); /* just one directory/folder */
4070 v.push_back (typedir);
4071 v.push_back (Glib::path_get_basename (old_path));
4073 return Glib::build_filename (v);
4077 Session::save_as (SaveAs& saveas)
4079 vector<string> files;
4080 string current_folder = Glib::path_get_dirname (_path);
4081 string new_folder = legalize_for_path (saveas.new_name);
4082 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4083 int64_t total_bytes = 0;
4087 int32_t internal_file_cnt = 0;
4089 vector<string> do_not_copy_extensions;
4090 do_not_copy_extensions.push_back (statefile_suffix);
4091 do_not_copy_extensions.push_back (pending_suffix);
4092 do_not_copy_extensions.push_back (backup_suffix);
4093 do_not_copy_extensions.push_back (temp_suffix);
4094 do_not_copy_extensions.push_back (history_suffix);
4096 /* get total size */
4098 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4100 /* need to clear this because
4101 * find_files_matching_filter() is cumulative
4106 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4108 all += files.size();
4110 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4112 g_stat ((*i).c_str(), &gsb);
4113 total_bytes += gsb.st_size;
4117 /* save old values so we can switch back if we are not switching to the new session */
4119 string old_path = _path;
4120 string old_name = _name;
4121 string old_snapshot = _current_snapshot_name;
4122 string old_sd = _session_dir->root_path();
4123 vector<string> old_search_path[DataType::num_types];
4124 string old_config_search_path[DataType::num_types];
4126 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4127 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4128 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4129 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4131 /* switch session directory */
4133 (*_session_dir) = to_dir;
4135 /* create new tree */
4137 if (!_session_dir->create()) {
4138 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4143 /* copy all relevant files. Find each location in session_dirs,
4144 * and copy files from there to target.
4147 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4149 /* need to clear this because
4150 * find_files_matching_filter() is cumulative
4155 const size_t prefix_len = (*sd).path.size();
4157 /* Work just on the files within this session dir */
4159 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4161 /* add dir separator to protect against collisions with
4162 * track names (e.g. track named "audiofiles" or
4166 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4167 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4168 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4170 /* copy all the files. Handling is different for media files
4171 than others because of the *silly* subtree we have below the interchange
4172 folder. That really was a bad idea, but I'm not fixing it as part of
4173 implementing ::save_as().
4176 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4178 std::string from = *i;
4181 string filename = Glib::path_get_basename (from);
4182 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4183 if (filename == ".DS_STORE") {
4188 if (from.find (audiofile_dir_string) != string::npos) {
4190 /* audio file: only copy if asked */
4192 if (saveas.include_media && saveas.copy_media) {
4194 string to = make_new_media_path (*i, to_dir, new_folder);
4196 info << "media file copying from " << from << " to " << to << endmsg;
4198 if (!copy_file (from, to)) {
4199 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4203 /* we found media files inside the session folder */
4205 internal_file_cnt++;
4207 } else if (from.find (midifile_dir_string) != string::npos) {
4209 /* midi file: always copy unless
4210 * creating an empty new session
4213 if (saveas.include_media) {
4215 string to = make_new_media_path (*i, to_dir, new_folder);
4217 info << "media file copying from " << from << " to " << to << endmsg;
4219 if (!copy_file (from, to)) {
4220 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4224 /* we found media files inside the session folder */
4226 internal_file_cnt++;
4228 } else if (from.find (analysis_dir_string) != string::npos) {
4230 /* make sure analysis dir exists in
4231 * new session folder, but we're not
4232 * copying analysis files here, see
4236 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4241 /* normal non-media file. Don't copy state, history, etc.
4244 bool do_copy = true;
4246 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4247 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4248 /* end of filename matches extension, do not copy file */
4254 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4255 /* don't copy peakfiles if
4256 * we're not copying media
4262 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4264 info << "attempting to make directory/folder " << to << endmsg;
4266 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4267 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4270 info << "attempting to copy " << from << " to " << to << endmsg;
4272 if (!copy_file (from, to)) {
4273 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4278 /* measure file size even if we're not going to copy so that our Progress
4279 signals are correct, since we included these do-not-copy files
4280 in the computation of the total size and file count.
4284 g_stat (from.c_str(), &gsb);
4285 copied += gsb.st_size;
4288 double fraction = (double) copied / total_bytes;
4290 bool keep_going = true;
4292 if (saveas.copy_media) {
4294 /* no need or expectation of this if
4295 * media is not being copied, because
4296 * it will be fast(ish).
4299 /* tell someone "X percent, file M of N"; M is one-based */
4301 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4309 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4315 /* copy optional folders, if any */
4317 string old = plugins_dir ();
4318 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4319 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4320 copy_files (old, newdir);
4323 old = externals_dir ();
4324 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4325 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4326 copy_files (old, newdir);
4329 old = automation_dir ();
4330 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4331 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4332 copy_files (old, newdir);
4335 if (saveas.include_media) {
4337 if (saveas.copy_media) {
4338 #ifndef PLATFORM_WINDOWS
4339 /* There are problems with analysis files on
4340 * Windows, because they used a colon in their
4341 * names as late as 4.0. Colons are not legal
4342 * under Windows even if NTFS allows them.
4344 * This is a tricky problem to solve so for
4345 * just don't copy these files. They will be
4346 * regenerated as-needed anyway, subject to the
4347 * existing issue that the filenames will be
4348 * rejected by Windows, which is a separate
4349 * problem (though related).
4352 /* only needed if we are copying media, since the
4353 * analysis data refers to media data
4356 old = analysis_dir ();
4357 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4358 string newdir = Glib::build_filename (to_dir, "analysis");
4359 copy_files (old, newdir);
4361 #endif /* PLATFORM_WINDOWS */
4367 _current_snapshot_name = saveas.new_name;
4368 _name = saveas.new_name;
4370 if (saveas.include_media && !saveas.copy_media) {
4372 /* reset search paths of the new session (which we're pretending to be right now) to
4373 include the original session search path, so we can still find all audio.
4376 if (internal_file_cnt) {
4377 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4378 ensure_search_path_includes (*s, DataType::AUDIO);
4381 /* we do not do this for MIDI because we copy
4382 all MIDI files if saveas.include_media is
4388 bool was_dirty = dirty ();
4390 save_state ("", false, false, !saveas.include_media);
4391 save_default_options ();
4393 if (saveas.copy_media && saveas.copy_external) {
4394 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4395 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4399 saveas.final_session_folder_name = _path;
4401 if (!saveas.switch_to) {
4403 /* switch back to the way things were */
4407 _current_snapshot_name = old_snapshot;
4409 (*_session_dir) = old_sd;
4415 if (internal_file_cnt) {
4416 /* reset these to their original values */
4417 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4418 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4423 /* prune session dirs, and update disk space statistics
4428 session_dirs.clear ();
4429 session_dirs.push_back (sp);
4430 refresh_disk_space ();
4432 /* ensure that all existing tracks reset their current capture source paths
4434 reset_write_sources (true, true);
4436 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4437 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4440 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4441 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4447 if (fs->within_session()) {
4448 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4449 fs->set_path (newpath);
4454 } catch (Glib::FileError& e) {
4456 saveas.failure_message = e.what();
4458 /* recursively remove all the directories */
4460 remove_directory (to_dir);
4468 saveas.failure_message = _("unknown reason");
4470 /* recursively remove all the directories */
4472 remove_directory (to_dir);