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)
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 */
699 tree.set_root (&get_state());
701 if (snapshot_name.empty()) {
702 snapshot_name = _current_snapshot_name;
703 } else if (switch_to_snapshot) {
704 _current_snapshot_name = snapshot_name;
709 /* proper save: use statefile_suffix (.ardour in English) */
711 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
713 /* make a backup copy of the old file */
715 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
716 // create_backup_file will log the error
722 /* pending save: use pending_suffix (.pending in English) */
723 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
726 std::string tmp_path(_session_dir->root_path());
727 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
729 cerr << "actually writing state to " << tmp_path << endl;
731 if (!tree.write (tmp_path)) {
732 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
733 if (g_remove (tmp_path.c_str()) != 0) {
734 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
735 tmp_path, g_strerror (errno)) << endmsg;
741 cerr << "renaming state to " << xml_path << endl;
743 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
744 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
745 tmp_path, xml_path, g_strerror(errno)) << endmsg;
746 if (g_remove (tmp_path.c_str()) != 0) {
747 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
748 tmp_path, g_strerror (errno)) << endmsg;
756 save_history (snapshot_name);
758 bool was_dirty = dirty();
760 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
763 DirtyChanged (); /* EMIT SIGNAL */
766 StateSaved (snapshot_name); /* EMIT SIGNAL */
773 Session::restore_state (string snapshot_name)
775 if (load_state (snapshot_name) == 0) {
776 set_state (*state_tree->root(), Stateful::loading_state_version);
783 Session::load_state (string snapshot_name)
788 state_was_pending = false;
790 /* check for leftover pending state from a crashed capture attempt */
792 std::string xmlpath(_session_dir->root_path());
793 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
795 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
797 /* there is pending state from a crashed capture attempt */
799 boost::optional<int> r = AskAboutPendingState();
800 if (r.get_value_or (1)) {
801 state_was_pending = true;
805 if (!state_was_pending) {
806 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
809 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
810 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
811 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
812 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
817 state_tree = new XMLTree;
821 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
823 if (!state_tree->read (xmlpath)) {
824 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
830 XMLNode& root (*state_tree->root());
832 if (root.name() != X_("Session")) {
833 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
839 const XMLProperty* prop;
841 if ((prop = root.property ("version")) == 0) {
842 /* no version implies very old version of Ardour */
843 Stateful::loading_state_version = 1000;
845 if (prop->value().find ('.') != string::npos) {
846 /* old school version format */
847 if (prop->value()[0] == '2') {
848 Stateful::loading_state_version = 2000;
850 Stateful::loading_state_version = 3000;
853 Stateful::loading_state_version = atoi (prop->value());
857 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
859 std::string backup_path(_session_dir->root_path());
860 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
861 backup_path = Glib::build_filename (backup_path, backup_filename);
863 // only create a backup for a given statefile version once
865 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
867 VersionMismatch (xmlpath, backup_path);
869 if (!copy_file (xmlpath, backup_path)) {;
879 Session::load_options (const XMLNode& node)
881 LocaleGuard lg (X_("C"));
882 config.set_variables (node);
887 Session::save_default_options ()
889 return config.save_state();
899 Session::get_template()
901 /* if we don't disable rec-enable, diskstreams
902 will believe they need to store their capture
903 sources in their state node.
906 disable_record (false);
912 Session::state (bool full_state)
914 XMLNode* node = new XMLNode("Session");
918 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
919 node->add_property("version", buf);
921 /* store configuration settings */
925 node->add_property ("name", _name);
926 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
927 node->add_property ("sample-rate", buf);
929 if (session_dirs.size() > 1) {
933 vector<space_and_path>::iterator i = session_dirs.begin();
934 vector<space_and_path>::iterator next;
936 ++i; /* skip the first one */
940 while (i != session_dirs.end()) {
944 if (next != session_dirs.end()) {
945 p += G_SEARCHPATH_SEPARATOR;
954 child = node->add_child ("Path");
955 child->add_content (p);
959 /* save the ID counter */
961 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
962 node->add_property ("id-counter", buf);
964 /* save the event ID counter */
966 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
967 node->add_property ("event-counter", buf);
969 /* various options */
971 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
972 if (!midi_port_nodes.empty()) {
973 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
974 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
975 midi_port_stuff->add_child_nocopy (**n);
977 node->add_child_nocopy (*midi_port_stuff);
980 node->add_child_nocopy (config.get_variables ());
982 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
984 child = node->add_child ("Sources");
987 Glib::Threads::Mutex::Lock sl (source_lock);
989 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
991 /* Don't save information about non-file Sources, or
992 * about non-destructive file sources that are empty
993 * and unused by any regions.
996 boost::shared_ptr<FileSource> fs;
998 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1000 if (!fs->destructive()) {
1001 if (fs->empty() && !fs->used()) {
1006 child->add_child_nocopy (siter->second->get_state());
1011 child = node->add_child ("Regions");
1014 Glib::Threads::Mutex::Lock rl (region_lock);
1015 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1016 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1017 boost::shared_ptr<Region> r = i->second;
1018 /* only store regions not attached to playlists */
1019 if (r->playlist() == 0) {
1020 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1021 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1023 child->add_child_nocopy (r->get_state ());
1028 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1030 if (!cassocs.empty()) {
1031 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1033 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1035 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1036 i->first->id().print (buf, sizeof (buf));
1037 can->add_property (X_("copy"), buf);
1038 i->second->id().print (buf, sizeof (buf));
1039 can->add_property (X_("original"), buf);
1040 ca->add_child_nocopy (*can);
1046 node->add_child_nocopy (_locations->get_state());
1048 // for a template, just create a new Locations, populate it
1049 // with the default start and end, and get the state for that.
1050 Locations loc (*this);
1051 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1052 range->set (max_framepos, 0);
1054 node->add_child_nocopy (loc.get_state());
1057 child = node->add_child ("Bundles");
1059 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1060 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1061 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1063 child->add_child_nocopy (b->get_state());
1068 child = node->add_child ("Routes");
1070 boost::shared_ptr<RouteList> r = routes.reader ();
1072 RoutePublicOrderSorter cmp;
1073 RouteList public_order (*r);
1074 public_order.sort (cmp);
1076 /* the sort should have put control outs first */
1079 assert (_monitor_out == public_order.front());
1082 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1083 if (!(*i)->is_auditioner()) {
1085 child->add_child_nocopy ((*i)->get_state());
1087 child->add_child_nocopy ((*i)->get_template());
1093 playlists->add_state (node, full_state);
1095 child = node->add_child ("RouteGroups");
1096 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1097 child->add_child_nocopy ((*i)->get_state());
1101 XMLNode* gain_child = node->add_child ("Click");
1102 gain_child->add_child_nocopy (_click_io->state (full_state));
1103 gain_child->add_child_nocopy (_click_gain->state (full_state));
1107 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1108 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1112 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1113 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1116 node->add_child_nocopy (_speakers->get_state());
1117 node->add_child_nocopy (_tempo_map->get_state());
1118 node->add_child_nocopy (get_control_protocol_state());
1121 node->add_child_copy (*_extra_xml);
1128 Session::get_control_protocol_state ()
1130 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1131 return cpm.get_state();
1135 Session::set_state (const XMLNode& node, int version)
1139 const XMLProperty* prop;
1142 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1144 if (node.name() != X_("Session")) {
1145 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1149 if ((prop = node.property ("name")) != 0) {
1150 _name = prop->value ();
1153 if ((prop = node.property (X_("sample-rate"))) != 0) {
1155 _nominal_frame_rate = atoi (prop->value());
1157 if (_nominal_frame_rate != _current_frame_rate) {
1158 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1159 if (r.get_value_or (0)) {
1165 setup_raid_path(_session_dir->root_path());
1167 if ((prop = node.property (X_("id-counter"))) != 0) {
1169 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1170 ID::init_counter (x);
1172 /* old sessions used a timebased counter, so fake
1173 the startup ID counter based on a standard
1178 ID::init_counter (now);
1181 if ((prop = node.property (X_("event-counter"))) != 0) {
1182 Evoral::init_event_id_counter (atoi (prop->value()));
1186 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1187 _midi_ports->set_midi_port_states (child->children());
1190 IO::disable_connecting ();
1192 Stateful::save_extra_xml (node);
1194 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1195 load_options (*child);
1196 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1197 load_options (*child);
1199 error << _("Session: XML state has no options section") << endmsg;
1202 if (version >= 3000) {
1203 if ((child = find_named_node (node, "Metadata")) == 0) {
1204 warning << _("Session: XML state has no metadata section") << endmsg;
1205 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1210 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1211 _speakers->set_state (*child, version);
1214 if ((child = find_named_node (node, "Sources")) == 0) {
1215 error << _("Session: XML state has no sources section") << endmsg;
1217 } else if (load_sources (*child)) {
1221 if ((child = find_named_node (node, "TempoMap")) == 0) {
1222 error << _("Session: XML state has no Tempo Map section") << endmsg;
1224 } else if (_tempo_map->set_state (*child, version)) {
1228 if ((child = find_named_node (node, "Locations")) == 0) {
1229 error << _("Session: XML state has no locations section") << endmsg;
1231 } else if (_locations->set_state (*child, version)) {
1235 locations_changed ();
1237 if (_session_range_location) {
1238 AudioFileSource::set_header_position_offset (_session_range_location->start());
1241 if ((child = find_named_node (node, "Regions")) == 0) {
1242 error << _("Session: XML state has no Regions section") << endmsg;
1244 } else if (load_regions (*child)) {
1248 if ((child = find_named_node (node, "Playlists")) == 0) {
1249 error << _("Session: XML state has no playlists section") << endmsg;
1251 } else if (playlists->load (*this, *child)) {
1255 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1257 } else if (playlists->load_unused (*this, *child)) {
1261 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1262 if (load_compounds (*child)) {
1267 if (version >= 3000) {
1268 if ((child = find_named_node (node, "Bundles")) == 0) {
1269 warning << _("Session: XML state has no bundles section") << endmsg;
1272 /* We can't load Bundles yet as they need to be able
1273 to convert from port names to Port objects, which can't happen until
1275 _bundle_xml_node = new XMLNode (*child);
1279 if (version < 3000) {
1280 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1281 error << _("Session: XML state has no diskstreams section") << endmsg;
1283 } else if (load_diskstreams_2X (*child, version)) {
1288 if ((child = find_named_node (node, "Routes")) == 0) {
1289 error << _("Session: XML state has no routes section") << endmsg;
1291 } else if (load_routes (*child, version)) {
1295 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1296 _diskstreams_2X.clear ();
1298 if (version >= 3000) {
1300 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1301 error << _("Session: XML state has no route groups section") << endmsg;
1303 } else if (load_route_groups (*child, version)) {
1307 } else if (version < 3000) {
1309 if ((child = find_named_node (node, "EditGroups")) == 0) {
1310 error << _("Session: XML state has no edit groups section") << endmsg;
1312 } else if (load_route_groups (*child, version)) {
1316 if ((child = find_named_node (node, "MixGroups")) == 0) {
1317 error << _("Session: XML state has no mix groups section") << endmsg;
1319 } else if (load_route_groups (*child, version)) {
1324 if ((child = find_named_node (node, "Click")) == 0) {
1325 warning << _("Session: XML state has no click section") << endmsg;
1326 } else if (_click_io) {
1327 setup_click_state (&node);
1330 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1331 ControlProtocolManager::instance().set_state (*child, version);
1334 update_have_rec_enabled_track ();
1336 /* here beginneth the second phase ... */
1338 StateReady (); /* EMIT SIGNAL */
1351 Session::load_routes (const XMLNode& node, int version)
1354 XMLNodeConstIterator niter;
1355 RouteList new_routes;
1357 nlist = node.children();
1361 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1363 boost::shared_ptr<Route> route;
1364 if (version < 3000) {
1365 route = XMLRouteFactory_2X (**niter, version);
1367 route = XMLRouteFactory (**niter, version);
1371 error << _("Session: cannot create Route from XML description.") << endmsg;
1375 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1377 new_routes.push_back (route);
1380 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1382 add_routes (new_routes, false, false, false);
1384 BootMessage (_("Finished adding tracks/busses"));
1389 boost::shared_ptr<Route>
1390 Session::XMLRouteFactory (const XMLNode& node, int version)
1392 boost::shared_ptr<Route> ret;
1394 if (node.name() != "Route") {
1398 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1400 DataType type = DataType::AUDIO;
1401 const XMLProperty* prop = node.property("default-type");
1404 type = DataType (prop->value());
1407 assert (type != DataType::NIL);
1411 boost::shared_ptr<Track> track;
1413 if (type == DataType::AUDIO) {
1414 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1416 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1419 if (track->init()) {
1423 if (track->set_state (node, version)) {
1427 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1428 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1433 enum Route::Flag flags = Route::Flag(0);
1434 const XMLProperty* prop = node.property("flags");
1436 flags = Route::Flag (string_2_enum (prop->value(), flags));
1439 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1441 if (r->init () == 0 && r->set_state (node, version) == 0) {
1442 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1443 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1452 boost::shared_ptr<Route>
1453 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1455 boost::shared_ptr<Route> ret;
1457 if (node.name() != "Route") {
1461 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1463 ds_prop = node.property (X_("diskstream"));
1466 DataType type = DataType::AUDIO;
1467 const XMLProperty* prop = node.property("default-type");
1470 type = DataType (prop->value());
1473 assert (type != DataType::NIL);
1477 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1478 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1482 if (i == _diskstreams_2X.end()) {
1483 error << _("Could not find diskstream for route") << endmsg;
1484 return boost::shared_ptr<Route> ();
1487 boost::shared_ptr<Track> track;
1489 if (type == DataType::AUDIO) {
1490 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1492 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1495 if (track->init()) {
1499 if (track->set_state (node, version)) {
1503 track->set_diskstream (*i);
1505 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1506 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1511 enum Route::Flag flags = Route::Flag(0);
1512 const XMLProperty* prop = node.property("flags");
1514 flags = Route::Flag (string_2_enum (prop->value(), flags));
1517 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1519 if (r->init () == 0 && r->set_state (node, version) == 0) {
1520 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1521 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1531 Session::load_regions (const XMLNode& node)
1534 XMLNodeConstIterator niter;
1535 boost::shared_ptr<Region> region;
1537 nlist = node.children();
1541 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1542 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1543 error << _("Session: cannot create Region from XML description.");
1544 const XMLProperty *name = (**niter).property("name");
1547 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1558 Session::load_compounds (const XMLNode& node)
1560 XMLNodeList calist = node.children();
1561 XMLNodeConstIterator caiter;
1562 XMLProperty *caprop;
1564 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1565 XMLNode* ca = *caiter;
1569 if ((caprop = ca->property (X_("original"))) == 0) {
1572 orig_id = caprop->value();
1574 if ((caprop = ca->property (X_("copy"))) == 0) {
1577 copy_id = caprop->value();
1579 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1580 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1582 if (!orig || !copy) {
1583 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1589 RegionFactory::add_compound_association (orig, copy);
1596 Session::load_nested_sources (const XMLNode& node)
1599 XMLNodeConstIterator niter;
1601 nlist = node.children();
1603 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1604 if ((*niter)->name() == "Source") {
1606 /* it may already exist, so don't recreate it unnecessarily
1609 XMLProperty* prop = (*niter)->property (X_("id"));
1611 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1615 ID source_id (prop->value());
1617 if (!source_by_id (source_id)) {
1620 SourceFactory::create (*this, **niter, true);
1622 catch (failed_constructor& err) {
1623 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1630 boost::shared_ptr<Region>
1631 Session::XMLRegionFactory (const XMLNode& node, bool full)
1633 const XMLProperty* type = node.property("type");
1637 const XMLNodeList& nlist = node.children();
1639 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1640 XMLNode *child = (*niter);
1641 if (child->name() == "NestedSource") {
1642 load_nested_sources (*child);
1646 if (!type || type->value() == "audio") {
1647 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1648 } else if (type->value() == "midi") {
1649 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1652 } catch (failed_constructor& err) {
1653 return boost::shared_ptr<Region> ();
1656 return boost::shared_ptr<Region> ();
1659 boost::shared_ptr<AudioRegion>
1660 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1662 const XMLProperty* prop;
1663 boost::shared_ptr<Source> source;
1664 boost::shared_ptr<AudioSource> as;
1666 SourceList master_sources;
1667 uint32_t nchans = 1;
1670 if (node.name() != X_("Region")) {
1671 return boost::shared_ptr<AudioRegion>();
1674 if ((prop = node.property (X_("channels"))) != 0) {
1675 nchans = atoi (prop->value().c_str());
1678 if ((prop = node.property ("name")) == 0) {
1679 cerr << "no name for this region\n";
1683 if ((prop = node.property (X_("source-0"))) == 0) {
1684 if ((prop = node.property ("source")) == 0) {
1685 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1686 return boost::shared_ptr<AudioRegion>();
1690 PBD::ID s_id (prop->value());
1692 if ((source = source_by_id (s_id)) == 0) {
1693 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1694 return boost::shared_ptr<AudioRegion>();
1697 as = boost::dynamic_pointer_cast<AudioSource>(source);
1699 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1700 return boost::shared_ptr<AudioRegion>();
1703 sources.push_back (as);
1705 /* pickup other channels */
1707 for (uint32_t n=1; n < nchans; ++n) {
1708 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1709 if ((prop = node.property (buf)) != 0) {
1711 PBD::ID id2 (prop->value());
1713 if ((source = source_by_id (id2)) == 0) {
1714 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1715 return boost::shared_ptr<AudioRegion>();
1718 as = boost::dynamic_pointer_cast<AudioSource>(source);
1720 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1721 return boost::shared_ptr<AudioRegion>();
1723 sources.push_back (as);
1727 for (uint32_t n = 0; n < nchans; ++n) {
1728 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1729 if ((prop = node.property (buf)) != 0) {
1731 PBD::ID id2 (prop->value());
1733 if ((source = source_by_id (id2)) == 0) {
1734 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1735 return boost::shared_ptr<AudioRegion>();
1738 as = boost::dynamic_pointer_cast<AudioSource>(source);
1740 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1741 return boost::shared_ptr<AudioRegion>();
1743 master_sources.push_back (as);
1748 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1750 /* a final detail: this is the one and only place that we know how long missing files are */
1752 if (region->whole_file()) {
1753 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1754 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1756 sfp->set_length (region->length());
1761 if (!master_sources.empty()) {
1762 if (master_sources.size() != nchans) {
1763 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1765 region->set_master_sources (master_sources);
1773 catch (failed_constructor& err) {
1774 return boost::shared_ptr<AudioRegion>();
1778 boost::shared_ptr<MidiRegion>
1779 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1781 const XMLProperty* prop;
1782 boost::shared_ptr<Source> source;
1783 boost::shared_ptr<MidiSource> ms;
1786 if (node.name() != X_("Region")) {
1787 return boost::shared_ptr<MidiRegion>();
1790 if ((prop = node.property ("name")) == 0) {
1791 cerr << "no name for this region\n";
1795 if ((prop = node.property (X_("source-0"))) == 0) {
1796 if ((prop = node.property ("source")) == 0) {
1797 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1798 return boost::shared_ptr<MidiRegion>();
1802 PBD::ID s_id (prop->value());
1804 if ((source = source_by_id (s_id)) == 0) {
1805 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1806 return boost::shared_ptr<MidiRegion>();
1809 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1811 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1812 return boost::shared_ptr<MidiRegion>();
1815 sources.push_back (ms);
1818 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1819 /* a final detail: this is the one and only place that we know how long missing files are */
1821 if (region->whole_file()) {
1822 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1823 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1825 sfp->set_length (region->length());
1833 catch (failed_constructor& err) {
1834 return boost::shared_ptr<MidiRegion>();
1839 Session::get_sources_as_xml ()
1842 XMLNode* node = new XMLNode (X_("Sources"));
1843 Glib::Threads::Mutex::Lock lm (source_lock);
1845 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1846 node->add_child_nocopy (i->second->get_state());
1853 Session::reset_write_sources (bool mark_write_complete, bool force)
1855 boost::shared_ptr<RouteList> rl = routes.reader();
1856 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1857 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1860 // block state saving
1861 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1862 tr->reset_write_sources(mark_write_complete, force);
1863 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1869 Session::load_sources (const XMLNode& node)
1872 XMLNodeConstIterator niter;
1873 boost::shared_ptr<Source> source; /* don't need this but it stops some
1874 * versions of gcc complaining about
1875 * discarded return values.
1878 nlist = node.children();
1882 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1885 if ((source = XMLSourceFactory (**niter)) == 0) {
1886 error << _("Session: cannot create Source from XML description.") << endmsg;
1889 } catch (MissingSource& err) {
1893 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1894 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1895 PROGRAM_NAME) << endmsg;
1899 if (!no_questions_about_missing_files) {
1900 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1905 switch (user_choice) {
1907 /* user added a new search location, so try again */
1912 /* user asked to quit the entire session load
1917 no_questions_about_missing_files = true;
1921 no_questions_about_missing_files = true;
1928 case DataType::AUDIO:
1929 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1932 case DataType::MIDI:
1933 /* The MIDI file is actually missing so
1934 * just create a new one in the same
1935 * location. Do not announce its
1939 if (!Glib::path_is_absolute (err.path)) {
1940 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
1942 /* this should be an unrecoverable error: we would be creating a MIDI file outside
1947 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
1948 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
1949 /* reset ID to match the missing one */
1950 source->set_id (**niter);
1951 /* Now we can announce it */
1952 SourceFactory::SourceCreated (source);
1963 boost::shared_ptr<Source>
1964 Session::XMLSourceFactory (const XMLNode& node)
1966 if (node.name() != "Source") {
1967 return boost::shared_ptr<Source>();
1971 /* note: do peak building in another thread when loading session state */
1972 return SourceFactory::create (*this, node, true);
1975 catch (failed_constructor& err) {
1976 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
1977 return boost::shared_ptr<Source>();
1982 Session::save_template (string template_name)
1986 if (_state_of_the_state & CannotSave) {
1990 std::string user_template_dir(user_template_directory());
1992 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
1993 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
1994 user_template_dir, g_strerror (errno)) << endmsg;
1998 tree.set_root (&get_template());
2000 std::string template_dir_path(user_template_dir);
2002 /* directory to put the template in */
2003 template_dir_path = Glib::build_filename (template_dir_path, template_name);
2005 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2006 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2007 template_dir_path) << endmsg;
2011 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2012 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2013 template_dir_path, g_strerror (errno)) << endmsg;
2018 std::string template_file_path(template_dir_path);
2019 template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
2021 if (!tree.write (template_file_path)) {
2022 error << _("template not saved") << endmsg;
2026 /* copy plugin state directory */
2028 std::string template_plugin_state_path(template_dir_path);
2029 template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
2031 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2032 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2033 template_plugin_state_path, g_strerror (errno)) << endmsg;
2037 copy_recurse (plugins_dir(), template_plugin_state_path);
2043 Session::refresh_disk_space ()
2045 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2047 Glib::Threads::Mutex::Lock lm (space_lock);
2049 /* get freespace on every FS that is part of the session path */
2051 _total_free_4k_blocks = 0;
2052 _total_free_4k_blocks_uncertain = false;
2054 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2056 struct statfs statfsbuf;
2057 statfs (i->path.c_str(), &statfsbuf);
2059 double const scale = statfsbuf.f_bsize / 4096.0;
2061 /* See if this filesystem is read-only */
2062 struct statvfs statvfsbuf;
2063 statvfs (i->path.c_str(), &statvfsbuf);
2065 /* f_bavail can be 0 if it is undefined for whatever
2066 filesystem we are looking at; Samba shares mounted
2067 via GVFS are an example of this.
2069 if (statfsbuf.f_bavail == 0) {
2070 /* block count unknown */
2072 i->blocks_unknown = true;
2073 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2074 /* read-only filesystem */
2076 i->blocks_unknown = false;
2078 /* read/write filesystem with known space */
2079 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2080 i->blocks_unknown = false;
2083 _total_free_4k_blocks += i->blocks;
2084 if (i->blocks_unknown) {
2085 _total_free_4k_blocks_uncertain = true;
2088 #elif defined PLATFORM_WINDOWS
2089 vector<string> scanned_volumes;
2090 vector<string>::iterator j;
2091 vector<space_and_path>::iterator i;
2092 DWORD nSectorsPerCluster, nBytesPerSector,
2093 nFreeClusters, nTotalClusters;
2097 _total_free_4k_blocks = 0;
2099 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2100 strncpy (disk_drive, (*i).path.c_str(), 3);
2104 volume_found = false;
2105 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2107 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2108 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2109 i->blocks = (uint32_t)(nFreeBytes / 4096);
2111 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2112 if (0 == j->compare(disk_drive)) {
2113 volume_found = true;
2118 if (!volume_found) {
2119 scanned_volumes.push_back(disk_drive);
2120 _total_free_4k_blocks += i->blocks;
2125 if (0 == _total_free_4k_blocks) {
2126 strncpy (disk_drive, path().c_str(), 3);
2129 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2131 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2132 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2133 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2140 Session::get_best_session_directory_for_new_audio ()
2142 vector<space_and_path>::iterator i;
2143 string result = _session_dir->root_path();
2145 /* handle common case without system calls */
2147 if (session_dirs.size() == 1) {
2151 /* OK, here's the algorithm we're following here:
2153 We want to select which directory to use for
2154 the next file source to be created. Ideally,
2155 we'd like to use a round-robin process so as to
2156 get maximum performance benefits from splitting
2157 the files across multiple disks.
2159 However, in situations without much diskspace, an
2160 RR approach may end up filling up a filesystem
2161 with new files while others still have space.
2162 Its therefore important to pay some attention to
2163 the freespace in the filesystem holding each
2164 directory as well. However, if we did that by
2165 itself, we'd keep creating new files in the file
2166 system with the most space until it was as full
2167 as all others, thus negating any performance
2168 benefits of this RAID-1 like approach.
2170 So, we use a user-configurable space threshold. If
2171 there are at least 2 filesystems with more than this
2172 much space available, we use RR selection between them.
2173 If not, then we pick the filesystem with the most space.
2175 This gets a good balance between the two
2179 refresh_disk_space ();
2181 int free_enough = 0;
2183 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2184 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2189 if (free_enough >= 2) {
2190 /* use RR selection process, ensuring that the one
2194 i = last_rr_session_dir;
2197 if (++i == session_dirs.end()) {
2198 i = session_dirs.begin();
2201 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2202 SessionDirectory sdir(i->path);
2203 if (sdir.create ()) {
2205 last_rr_session_dir = i;
2210 } while (i != last_rr_session_dir);
2214 /* pick FS with the most freespace (and that
2215 seems to actually work ...)
2218 vector<space_and_path> sorted;
2219 space_and_path_ascending_cmp cmp;
2221 sorted = session_dirs;
2222 sort (sorted.begin(), sorted.end(), cmp);
2224 for (i = sorted.begin(); i != sorted.end(); ++i) {
2225 SessionDirectory sdir(i->path);
2226 if (sdir.create ()) {
2228 last_rr_session_dir = i;
2238 Session::automation_dir () const
2240 return Glib::build_filename (_path, "automation");
2244 Session::analysis_dir () const
2246 return Glib::build_filename (_path, "analysis");
2250 Session::plugins_dir () const
2252 return Glib::build_filename (_path, "plugins");
2256 Session::externals_dir () const
2258 return Glib::build_filename (_path, "externals");
2262 Session::load_bundles (XMLNode const & node)
2264 XMLNodeList nlist = node.children();
2265 XMLNodeConstIterator niter;
2269 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2270 if ((*niter)->name() == "InputBundle") {
2271 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2272 } else if ((*niter)->name() == "OutputBundle") {
2273 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2275 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2284 Session::load_route_groups (const XMLNode& node, int version)
2286 XMLNodeList nlist = node.children();
2287 XMLNodeConstIterator niter;
2291 if (version >= 3000) {
2293 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2294 if ((*niter)->name() == "RouteGroup") {
2295 RouteGroup* rg = new RouteGroup (*this, "");
2296 add_route_group (rg);
2297 rg->set_state (**niter, version);
2301 } else if (version < 3000) {
2303 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2304 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2305 RouteGroup* rg = new RouteGroup (*this, "");
2306 add_route_group (rg);
2307 rg->set_state (**niter, version);
2316 state_file_filter (const string &str, void* /*arg*/)
2318 return (str.length() > strlen(statefile_suffix) &&
2319 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2323 remove_end(string state)
2325 string statename(state);
2327 string::size_type start,end;
2328 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2329 statename = statename.substr (start+1);
2332 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2333 end = statename.length();
2336 return string(statename.substr (0, end));
2340 Session::possible_states (string path)
2342 vector<string> states;
2343 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2345 transform(states.begin(), states.end(), states.begin(), remove_end);
2347 sort (states.begin(), states.end());
2353 Session::possible_states () const
2355 return possible_states(_path);
2359 Session::add_route_group (RouteGroup* g)
2361 _route_groups.push_back (g);
2362 route_group_added (g); /* EMIT SIGNAL */
2364 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2365 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2366 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2372 Session::remove_route_group (RouteGroup& rg)
2374 list<RouteGroup*>::iterator i;
2376 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2377 _route_groups.erase (i);
2380 route_group_removed (); /* EMIT SIGNAL */
2384 /** Set a new order for our route groups, without adding or removing any.
2385 * @param groups Route group list in the new order.
2388 Session::reorder_route_groups (list<RouteGroup*> groups)
2390 _route_groups = groups;
2392 route_groups_reordered (); /* EMIT SIGNAL */
2398 Session::route_group_by_name (string name)
2400 list<RouteGroup *>::iterator i;
2402 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2403 if ((*i)->name() == name) {
2411 Session::all_route_group() const
2413 return *_all_route_group;
2417 Session::add_commands (vector<Command*> const & cmds)
2419 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2425 Session::begin_reversible_command (const string& name)
2427 begin_reversible_command (g_quark_from_string (name.c_str ()));
2430 /** Begin a reversible command using a GQuark to identify it.
2431 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2432 * but there must be as many begin...()s as there are commit...()s.
2435 Session::begin_reversible_command (GQuark q)
2437 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2438 to hold all the commands that are committed. This keeps the order of
2439 commands correct in the history.
2442 if (_current_trans == 0) {
2443 /* start a new transaction */
2444 assert (_current_trans_quarks.empty ());
2445 _current_trans = new UndoTransaction();
2446 _current_trans->set_name (g_quark_to_string (q));
2449 _current_trans_quarks.push_front (q);
2453 Session::abort_reversible_command ()
2455 if (_current_trans != 0) {
2456 _current_trans->clear();
2457 delete _current_trans;
2459 _current_trans_quarks.clear();
2464 Session::commit_reversible_command (Command *cmd)
2466 assert (_current_trans);
2467 assert (!_current_trans_quarks.empty ());
2472 _current_trans->add_command (cmd);
2475 _current_trans_quarks.pop_front ();
2477 if (!_current_trans_quarks.empty ()) {
2478 /* the transaction we're committing is not the top-level one */
2482 if (_current_trans->empty()) {
2483 /* no commands were added to the transaction, so just get rid of it */
2484 delete _current_trans;
2489 gettimeofday (&now, 0);
2490 _current_trans->set_timestamp (now);
2492 _history.add (_current_trans);
2497 accept_all_audio_files (const string& path, void* /*arg*/)
2499 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2503 if (!AudioFileSource::safe_audio_file_extension (path)) {
2511 accept_all_midi_files (const string& path, void* /*arg*/)
2513 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2517 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2518 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2519 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2523 accept_all_state_files (const string& path, void* /*arg*/)
2525 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2529 std::string const statefile_ext (statefile_suffix);
2530 if (path.length() >= statefile_ext.length()) {
2531 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2538 Session::find_all_sources (string path, set<string>& result)
2543 if (!tree.read (path)) {
2547 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2552 XMLNodeConstIterator niter;
2554 nlist = node->children();
2558 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2562 if ((prop = (*niter)->property (X_("type"))) == 0) {
2566 DataType type (prop->value());
2568 if ((prop = (*niter)->property (X_("name"))) == 0) {
2572 if (Glib::path_is_absolute (prop->value())) {
2573 /* external file, ignore */
2581 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2582 result.insert (found_path);
2590 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2592 vector<string> state_files;
2594 string this_snapshot_path;
2600 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2601 ripped = ripped.substr (0, ripped.length() - 1);
2604 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2606 if (state_files.empty()) {
2611 this_snapshot_path = _path;
2612 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2613 this_snapshot_path += statefile_suffix;
2615 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2617 if (exclude_this_snapshot && *i == this_snapshot_path) {
2621 if (find_all_sources (*i, result) < 0) {
2629 struct RegionCounter {
2630 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2631 AudioSourceList::iterator iter;
2632 boost::shared_ptr<Region> region;
2635 RegionCounter() : count (0) {}
2639 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2641 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2642 return r.get_value_or (1);
2646 Session::cleanup_regions ()
2648 bool removed = false;
2649 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2651 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2653 uint32_t used = playlists->region_use_count (i->second);
2655 if (used == 0 && !i->second->automatic ()) {
2657 RegionFactory::map_remove (i->second);
2662 // re-check to remove parent references of compound regions
2663 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2664 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2667 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2668 if (0 == playlists->region_use_count (i->second)) {
2669 RegionFactory::map_remove (i->second);
2674 /* dump the history list */
2681 Session::cleanup_sources (CleanupReport& rep)
2683 // FIXME: needs adaptation to midi
2685 vector<boost::shared_ptr<Source> > dead_sources;
2688 vector<string> candidates;
2689 vector<string> unused;
2690 set<string> all_sources;
2699 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2701 /* consider deleting all unused playlists */
2703 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2708 /* sync the "all regions" property of each playlist with its current state
2711 playlists->sync_all_regions_with_regions ();
2713 /* find all un-used sources */
2718 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2720 SourceMap::iterator tmp;
2725 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2729 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2730 dead_sources.push_back (i->second);
2731 i->second->drop_references ();
2737 /* build a list of all the possible audio directories for the session */
2739 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2740 SessionDirectory sdir ((*i).path);
2741 asp += sdir.sound_path();
2743 audio_path += asp.to_string();
2746 /* build a list of all the possible midi directories for the session */
2748 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2749 SessionDirectory sdir ((*i).path);
2750 msp += sdir.midi_path();
2752 midi_path += msp.to_string();
2754 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2755 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2757 /* find all sources, but don't use this snapshot because the
2758 state file on disk still references sources we may have already
2762 find_all_sources_across_snapshots (all_sources, true);
2764 /* add our current source list
2767 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2768 boost::shared_ptr<FileSource> fs;
2769 SourceMap::iterator tmp = i;
2772 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2774 if (!fs->is_stub()) {
2776 if (playlists->source_use_count (fs) != 0) {
2777 all_sources.insert (fs->path());
2780 /* we might not remove this source from disk, because it may be used
2781 by other snapshots, but its not being used in this version
2782 so lets get rid of it now, along with any representative regions
2786 RegionFactory::remove_regions_using_source (i->second);
2795 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2800 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2802 tmppath1 = canonical_path (spath);
2803 tmppath2 = canonical_path ((*i));
2805 if (tmppath1 == tmppath2) {
2812 unused.push_back (spath);
2816 /* now try to move all unused files into the "dead" directory(ies) */
2818 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2819 struct stat statbuf;
2823 /* don't move the file across filesystems, just
2824 stick it in the `dead_dir_name' directory
2825 on whichever filesystem it was already on.
2828 if ((*x).find ("/sounds/") != string::npos) {
2830 /* old school, go up 1 level */
2832 newpath = Glib::path_get_dirname (*x); // "sounds"
2833 newpath = Glib::path_get_dirname (newpath); // "session-name"
2837 /* new school, go up 4 levels */
2839 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2840 newpath = Glib::path_get_dirname (newpath); // "session-name"
2841 newpath = Glib::path_get_dirname (newpath); // "interchange"
2842 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2845 newpath = Glib::build_filename (newpath, dead_dir_name);
2847 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2848 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2852 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2854 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2856 /* the new path already exists, try versioning */
2858 char buf[PATH_MAX+1];
2862 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2865 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2866 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2870 if (version == 999) {
2871 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2875 newpath = newpath_v;
2880 /* it doesn't exist, or we can't read it or something */
2884 stat ((*x).c_str(), &statbuf);
2886 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2887 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2888 (*x), newpath, strerror (errno))
2893 /* see if there an easy to find peakfile for this file, and remove it.
2896 string base = basename_nosuffix (*x);
2897 base += "%A"; /* this is what we add for the channel suffix of all native files,
2898 or for the first channel of embedded files. it will miss
2899 some peakfiles for other channels
2901 string peakpath = peak_path (base);
2903 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2904 if (::g_unlink (peakpath.c_str()) != 0) {
2905 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2906 peakpath, _path, strerror (errno))
2908 /* try to back out */
2909 ::rename (newpath.c_str(), _path.c_str());
2914 rep.paths.push_back (*x);
2915 rep.space += statbuf.st_size;
2918 /* dump the history list */
2922 /* save state so we don't end up a session file
2923 referring to non-existent sources.
2930 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2936 Session::cleanup_trash_sources (CleanupReport& rep)
2938 // FIXME: needs adaptation for MIDI
2940 vector<space_and_path>::iterator i;
2946 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2948 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2950 clear_directory (dead_dir, &rep.space, &rep.paths);
2957 Session::set_dirty ()
2959 /* never mark session dirty during loading */
2961 if (_state_of_the_state & Loading) {
2965 bool was_dirty = dirty();
2967 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2971 DirtyChanged(); /* EMIT SIGNAL */
2977 Session::set_clean ()
2979 bool was_dirty = dirty();
2981 _state_of_the_state = Clean;
2985 DirtyChanged(); /* EMIT SIGNAL */
2990 Session::set_deletion_in_progress ()
2992 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2996 Session::clear_deletion_in_progress ()
2998 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3002 Session::add_controllable (boost::shared_ptr<Controllable> c)
3004 /* this adds a controllable to the list managed by the Session.
3005 this is a subset of those managed by the Controllable class
3006 itself, and represents the only ones whose state will be saved
3007 as part of the session.
3010 Glib::Threads::Mutex::Lock lm (controllables_lock);
3011 controllables.insert (c);
3014 struct null_deleter { void operator()(void const *) const {} };
3017 Session::remove_controllable (Controllable* c)
3019 if (_state_of_the_state & Deletion) {
3023 Glib::Threads::Mutex::Lock lm (controllables_lock);
3025 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3027 if (x != controllables.end()) {
3028 controllables.erase (x);
3032 boost::shared_ptr<Controllable>
3033 Session::controllable_by_id (const PBD::ID& id)
3035 Glib::Threads::Mutex::Lock lm (controllables_lock);
3037 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3038 if ((*i)->id() == id) {
3043 return boost::shared_ptr<Controllable>();
3046 boost::shared_ptr<Controllable>
3047 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3049 boost::shared_ptr<Controllable> c;
3050 boost::shared_ptr<Route> r;
3052 switch (desc.top_level_type()) {
3053 case ControllableDescriptor::NamedRoute:
3055 std::string str = desc.top_level_name();
3056 if (str == "Master" || str == "master") {
3058 } else if (str == "control" || str == "listen") {
3061 r = route_by_name (desc.top_level_name());
3066 case ControllableDescriptor::RemoteControlID:
3067 r = route_by_remote_id (desc.rid());
3075 switch (desc.subtype()) {
3076 case ControllableDescriptor::Gain:
3077 c = r->gain_control ();
3080 case ControllableDescriptor::Trim:
3081 c = r->trim()->gain_control ();
3084 case ControllableDescriptor::Solo:
3085 c = r->solo_control();
3088 case ControllableDescriptor::Mute:
3089 c = r->mute_control();
3092 case ControllableDescriptor::Recenable:
3094 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3097 c = t->rec_enable_control ();
3102 case ControllableDescriptor::PanDirection:
3104 c = r->pannable()->pan_azimuth_control;
3108 case ControllableDescriptor::PanWidth:
3110 c = r->pannable()->pan_width_control;
3114 case ControllableDescriptor::PanElevation:
3116 c = r->pannable()->pan_elevation_control;
3120 case ControllableDescriptor::Balance:
3121 /* XXX simple pan control */
3124 case ControllableDescriptor::PluginParameter:
3126 uint32_t plugin = desc.target (0);
3127 uint32_t parameter_index = desc.target (1);
3129 /* revert to zero based counting */
3135 if (parameter_index > 0) {
3139 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3142 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3143 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3148 case ControllableDescriptor::SendGain:
3150 uint32_t send = desc.target (0);
3152 /* revert to zero-based counting */
3158 boost::shared_ptr<Processor> p = r->nth_send (send);
3161 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3162 boost::shared_ptr<Amp> a = s->amp();
3165 c = s->amp()->gain_control();
3172 /* relax and return a null pointer */
3180 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3183 Stateful::add_instant_xml (node, _path);
3186 if (write_to_config) {
3187 Config->add_instant_xml (node);
3192 Session::instant_xml (const string& node_name)
3194 return Stateful::instant_xml (node_name, _path);
3198 Session::save_history (string snapshot_name)
3206 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3207 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3211 if (snapshot_name.empty()) {
3212 snapshot_name = _current_snapshot_name;
3215 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3216 const string backup_filename = history_filename + backup_suffix;
3217 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3218 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3220 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3221 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3222 error << _("could not backup old history file, current history not saved") << endmsg;
3227 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3229 if (!tree.write (xml_path))
3231 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3233 if (g_remove (xml_path.c_str()) != 0) {
3234 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3235 xml_path, g_strerror (errno)) << endmsg;
3237 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3238 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3239 backup_path, g_strerror (errno)) << endmsg;
3249 Session::restore_history (string snapshot_name)
3253 if (snapshot_name.empty()) {
3254 snapshot_name = _current_snapshot_name;
3257 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3258 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3260 info << "Loading history from " << xml_path << endmsg;
3262 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3263 info << string_compose (_("%1: no history file \"%2\" for this session."),
3264 _name, xml_path) << endmsg;
3268 if (!tree.read (xml_path)) {
3269 error << string_compose (_("Could not understand session history file \"%1\""),
3270 xml_path) << endmsg;
3277 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3280 UndoTransaction* ut = new UndoTransaction ();
3283 ut->set_name(t->property("name")->value());
3284 stringstream ss(t->property("tv-sec")->value());
3286 ss.str(t->property("tv-usec")->value());
3288 ut->set_timestamp(tv);
3290 for (XMLNodeConstIterator child_it = t->children().begin();
3291 child_it != t->children().end(); child_it++)
3293 XMLNode *n = *child_it;
3296 if (n->name() == "MementoCommand" ||
3297 n->name() == "MementoUndoCommand" ||
3298 n->name() == "MementoRedoCommand") {
3300 if ((c = memento_command_factory(n))) {
3304 } else if (n->name() == "NoteDiffCommand") {
3305 PBD::ID id (n->property("midi-source")->value());
3306 boost::shared_ptr<MidiSource> midi_source =
3307 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3309 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3311 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3314 } else if (n->name() == "SysExDiffCommand") {
3316 PBD::ID id (n->property("midi-source")->value());
3317 boost::shared_ptr<MidiSource> midi_source =
3318 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3320 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3322 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3325 } else if (n->name() == "PatchChangeDiffCommand") {
3327 PBD::ID id (n->property("midi-source")->value());
3328 boost::shared_ptr<MidiSource> midi_source =
3329 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3331 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3333 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3336 } else if (n->name() == "StatefulDiffCommand") {
3337 if ((c = stateful_diff_command_factory (n))) {
3338 ut->add_command (c);
3341 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3352 Session::config_changed (std::string p, bool ours)
3358 if (p == "seamless-loop") {
3360 } else if (p == "rf-speed") {
3362 } else if (p == "auto-loop") {
3364 } else if (p == "auto-input") {
3366 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3367 /* auto-input only makes a difference if we're rolling */
3368 set_track_monitor_input_status (!config.get_auto_input());
3371 } else if (p == "punch-in") {
3375 if ((location = _locations->auto_punch_location()) != 0) {
3377 if (config.get_punch_in ()) {
3378 replace_event (SessionEvent::PunchIn, location->start());
3380 remove_event (location->start(), SessionEvent::PunchIn);
3384 } else if (p == "punch-out") {
3388 if ((location = _locations->auto_punch_location()) != 0) {
3390 if (config.get_punch_out()) {
3391 replace_event (SessionEvent::PunchOut, location->end());
3393 clear_events (SessionEvent::PunchOut);
3397 } else if (p == "edit-mode") {
3399 Glib::Threads::Mutex::Lock lm (playlists->lock);
3401 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3402 (*i)->set_edit_mode (Config->get_edit_mode ());
3405 } else if (p == "use-video-sync") {
3407 waiting_for_sync_offset = config.get_use_video_sync();
3409 } else if (p == "mmc-control") {
3411 //poke_midi_thread ();
3413 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3415 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3417 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3419 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3421 } else if (p == "midi-control") {
3423 //poke_midi_thread ();
3425 } else if (p == "raid-path") {
3427 setup_raid_path (config.get_raid_path());
3429 } else if (p == "timecode-format") {
3433 } else if (p == "video-pullup") {
3437 } else if (p == "seamless-loop") {
3439 if (play_loop && transport_rolling()) {
3440 // to reset diskstreams etc
3441 request_play_loop (true);
3444 } else if (p == "rf-speed") {
3446 cumulative_rf_motion = 0;
3449 } else if (p == "click-sound") {
3451 setup_click_sounds (1);
3453 } else if (p == "click-emphasis-sound") {
3455 setup_click_sounds (-1);
3457 } else if (p == "clicking") {
3459 if (Config->get_clicking()) {
3460 if (_click_io && click_data) { // don't require emphasis data
3467 } else if (p == "click-gain") {
3470 _click_gain->set_gain (Config->get_click_gain(), this);
3473 } else if (p == "send-mtc") {
3475 if (Config->get_send_mtc ()) {
3476 /* mark us ready to send */
3477 next_quarter_frame_to_send = 0;
3480 } else if (p == "send-mmc") {
3482 _mmc->enable_send (Config->get_send_mmc ());
3484 } else if (p == "midi-feedback") {
3486 session_midi_feedback = Config->get_midi_feedback();
3488 } else if (p == "jack-time-master") {
3490 engine().reset_timebase ();
3492 } else if (p == "native-file-header-format") {
3494 if (!first_file_header_format_reset) {
3495 reset_native_file_format ();
3498 first_file_header_format_reset = false;
3500 } else if (p == "native-file-data-format") {
3502 if (!first_file_data_format_reset) {
3503 reset_native_file_format ();
3506 first_file_data_format_reset = false;
3508 } else if (p == "external-sync") {
3509 if (!config.get_external_sync()) {
3510 drop_sync_source ();
3512 switch_to_sync_source (Config->get_sync_source());
3514 } else if (p == "denormal-model") {
3516 } else if (p == "history-depth") {
3517 set_history_depth (Config->get_history_depth());
3518 } else if (p == "remote-model") {
3519 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3522 } else if (p == "initial-program-change") {
3524 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3527 buf[0] = MIDI::program; // channel zero by default
3528 buf[1] = (Config->get_initial_program_change() & 0x7f);
3530 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3532 } else if (p == "solo-mute-override") {
3533 // catch_up_on_solo_mute_override ();
3534 } else if (p == "listen-position" || p == "pfl-position") {
3535 listen_position_changed ();
3536 } else if (p == "solo-control-is-listen-control") {
3537 solo_control_mode_changed ();
3538 } else if (p == "solo-mute-gain") {
3539 _solo_cut_control->Changed();
3540 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3541 last_timecode_valid = false;
3542 } else if (p == "playback-buffer-seconds") {
3543 AudioSource::allocate_working_buffers (frame_rate());
3544 } else if (p == "ltc-source-port") {
3545 reconnect_ltc_input ();
3546 } else if (p == "ltc-sink-port") {
3547 reconnect_ltc_output ();
3548 } else if (p == "timecode-generator-offset") {
3549 ltc_tx_parse_offset();
3556 Session::set_history_depth (uint32_t d)
3558 _history.set_depth (d);
3562 Session::load_diskstreams_2X (XMLNode const & node, int)
3565 XMLNodeConstIterator citer;
3567 clist = node.children();
3569 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3572 /* diskstreams added automatically by DiskstreamCreated handler */
3573 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3574 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3575 _diskstreams_2X.push_back (dsp);
3577 error << _("Session: unknown diskstream type in XML") << endmsg;
3581 catch (failed_constructor& err) {
3582 error << _("Session: could not load diskstream via XML state") << endmsg;
3590 /** Connect things to the MMC object */
3592 Session::setup_midi_machine_control ()
3594 _mmc = new MIDI::MachineControl;
3595 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3597 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3598 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3599 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3600 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3601 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3602 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3603 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3604 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3605 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3606 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3607 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3608 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3609 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3611 /* also handle MIDI SPP because its so common */
3613 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3614 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3615 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3618 boost::shared_ptr<Controllable>
3619 Session::solo_cut_control() const
3621 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3622 controls in Ardour that currently get presented to the user in the GUI that require
3623 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3625 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3626 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3630 return _solo_cut_control;
3634 Session::rename (const std::string& new_name)
3636 string legal_name = legalize_for_path (new_name);
3642 string const old_sources_root = _session_dir->sources_root();
3644 if (!_writable || (_state_of_the_state & CannotSave)) {
3645 error << _("Cannot rename read-only session.") << endmsg;
3646 return 0; // don't show "messed up" warning
3648 if (record_status() == Recording) {
3649 error << _("Cannot rename session while recording") << endmsg;
3650 return 0; // don't show "messed up" warning
3653 StateProtector stp (this);
3658 * interchange subdirectory
3662 * Backup files are left unchanged and not renamed.
3665 /* pass one: not 100% safe check that the new directory names don't
3669 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3673 /* this is a stupid hack because Glib::path_get_dirname() is
3674 * lexical-only, and so passing it /a/b/c/ gives a different
3675 * result than passing it /a/b/c ...
3678 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3679 oldstr = oldstr.substr (0, oldstr.length() - 1);
3682 string base = Glib::path_get_dirname (oldstr);
3684 newstr = Glib::build_filename (base, legal_name);
3686 cerr << "Looking for " << newstr << endl;
3688 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3689 cerr << " exists\n";
3698 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3704 /* this is a stupid hack because Glib::path_get_dirname() is
3705 * lexical-only, and so passing it /a/b/c/ gives a different
3706 * result than passing it /a/b/c ...
3709 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3710 oldstr = oldstr.substr (0, oldstr.length() - 1);
3713 string base = Glib::path_get_dirname (oldstr);
3714 newstr = Glib::build_filename (base, legal_name);
3716 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3718 cerr << "Rename " << oldstr << " => " << newstr << endl;
3719 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3720 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3721 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3725 /* Reset path in "session dirs" */
3730 /* reset primary SessionDirectory object */
3733 (*_session_dir) = newstr;
3738 /* now rename directory below session_dir/interchange */
3740 string old_interchange_dir;
3741 string new_interchange_dir;
3743 /* use newstr here because we renamed the path
3744 * (folder/directory) that used to be oldstr to newstr above
3747 v.push_back (newstr);
3748 v.push_back (interchange_dir_name);
3749 v.push_back (Glib::path_get_basename (oldstr));
3751 old_interchange_dir = Glib::build_filename (v);
3754 v.push_back (newstr);
3755 v.push_back (interchange_dir_name);
3756 v.push_back (legal_name);
3758 new_interchange_dir = Glib::build_filename (v);
3760 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3762 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3763 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3764 old_interchange_dir, new_interchange_dir,
3767 error << string_compose (_("renaming %s as %2 failed (%3)"),
3768 old_interchange_dir, new_interchange_dir,
3777 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3778 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3780 cerr << "Rename " << oldstr << " => " << newstr << endl;
3782 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3783 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3784 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3790 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3792 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3793 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3795 cerr << "Rename " << oldstr << " => " << newstr << endl;
3797 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3798 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3799 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3804 /* remove old name from recent sessions */
3805 remove_recent_sessions (_path);
3808 /* update file source paths */
3810 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3811 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3813 string p = fs->path ();
3814 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3816 SourceFactory::setup_peakfile(i->second, true);
3820 _current_snapshot_name = new_name;
3825 /* save state again to get everything just right */
3827 save_state (_current_snapshot_name);
3829 /* add to recent sessions */
3831 store_recent_sessions (new_name, _path);
3837 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3839 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3843 if (!tree.read (xmlpath)) {
3851 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3854 bool found_sr = false;
3855 bool found_data_format = false;
3857 if (get_session_info_from_path (tree, xmlpath)) {
3863 const XMLProperty* prop;
3864 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3865 sample_rate = atoi (prop->value());
3869 const XMLNodeList& children (tree.root()->children());
3870 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3871 const XMLNode* child = *c;
3872 if (child->name() == "Config") {
3873 const XMLNodeList& options (child->children());
3874 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3875 const XMLNode* option = *oc;
3876 const XMLProperty* name = option->property("name");
3882 if (name->value() == "native-file-data-format") {
3883 const XMLProperty* value = option->property ("value");
3885 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3887 found_data_format = true;
3893 if (found_data_format) {
3898 return !(found_sr && found_data_format); // zero if they are both found
3901 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
3902 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
3905 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
3909 SourcePathMap source_path_map;
3911 boost::shared_ptr<AudioFileSource> afs;
3916 Glib::Threads::Mutex::Lock lm (source_lock);
3918 cerr << " total sources = " << sources.size();
3920 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3921 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3927 if (fs->within_session()) {
3931 if (source_path_map.find (fs->path()) != source_path_map.end()) {
3932 source_path_map[fs->path()].push_back (fs);
3934 SeveralFileSources v;
3936 source_path_map.insert (make_pair (fs->path(), v));
3942 cerr << " fsources = " << total << endl;
3944 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
3946 /* tell caller where we are */
3948 string old_path = i->first;
3950 callback (n, total, old_path);
3952 cerr << old_path << endl;
3956 switch (i->second.front()->type()) {
3957 case DataType::AUDIO:
3958 new_path = new_audio_source_path_for_embedded (old_path);
3961 case DataType::MIDI:
3962 /* XXX not implemented yet */
3966 if (new_path.empty()) {
3970 cerr << "Move " << old_path << " => " << new_path << endl;
3972 if (!copy_file (old_path, new_path)) {
3973 cerr << "failed !\n";
3977 /* make sure we stop looking in the external
3978 dir/folder. Remember, this is an all-or-nothing
3979 operations, it doesn't merge just some files.
3981 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
3983 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
3984 (*f)->set_path (new_path);
3989 save_state ("", false, false);
3995 bool accept_all_files (string const &, void *)
4001 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4003 /* 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.
4008 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4010 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4012 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4014 v.push_back (new_session_folder); /* full path */
4015 v.push_back (interchange_dir_name);
4016 v.push_back (new_session_path); /* just one directory/folder */
4017 v.push_back (typedir);
4018 v.push_back (Glib::path_get_basename (old_path));
4020 return Glib::build_filename (v);
4024 Session::save_as (SaveAs& saveas)
4026 vector<string> files;
4027 string current_folder = Glib::path_get_dirname (_path);
4028 string new_folder = legalize_for_path (saveas.new_name);
4029 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4030 int64_t total_bytes = 0;
4034 int32_t internal_file_cnt = 0;
4036 vector<string> do_not_copy_extensions;
4037 do_not_copy_extensions.push_back (statefile_suffix);
4038 do_not_copy_extensions.push_back (pending_suffix);
4039 do_not_copy_extensions.push_back (backup_suffix);
4040 do_not_copy_extensions.push_back (temp_suffix);
4041 do_not_copy_extensions.push_back (history_suffix);
4043 /* get total size */
4045 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4047 /* need to clear this because
4048 * find_files_matching_filter() is cumulative
4053 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4055 all += files.size();
4057 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4059 g_stat ((*i).c_str(), &gsb);
4060 total_bytes += gsb.st_size;
4064 /* save old values so we can switch back if we are not switching to the new session */
4066 string old_path = _path;
4067 string old_name = _name;
4068 string old_snapshot = _current_snapshot_name;
4069 string old_sd = _session_dir->root_path();
4070 vector<string> old_search_path[DataType::num_types];
4071 string old_config_search_path[DataType::num_types];
4073 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4074 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4075 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4076 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4078 /* switch session directory */
4080 (*_session_dir) = to_dir;
4082 /* create new tree */
4084 if (!_session_dir->create()) {
4085 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4090 /* copy all media files. Find each location in
4091 * session_dirs, and copy files from there to
4095 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4097 /* need to clear this because
4098 * find_files_matching_filter() is cumulative
4103 const size_t prefix_len = (*sd).path.size();
4105 /* Work just on the files within this session dir */
4107 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4109 /* copy all the files. Handling is different for media files
4110 than others because of the *silly* subtree we have below the interchange
4111 folder. That really was a bad idea, but I'm not fixing it as part of
4112 implementing ::save_as().
4115 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4117 std::string from = *i;
4119 if ((*i).find (interchange_dir_name) != string::npos) {
4123 if (saveas.copy_media) {
4125 string to = make_new_media_path (*i, to_dir, new_folder);
4127 if (!copy_file (from, to)) {
4128 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4132 /* we found media files inside the session folder */
4134 internal_file_cnt++;
4138 /* normal non-media file. Don't copy state, history, etc.
4141 bool do_copy = true;
4143 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4144 if (((*i).length() > (*v).length()) && ((*i).find (*v) == (*i).length() - (*v).length())) {
4145 /* end of filename matches extension, do not copy file */
4152 string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
4154 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4155 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4158 if (!copy_file (from, to)) {
4159 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4164 /* measure file size even if we're not going to copy so that our Progress
4165 signals are correct, since we included these do-not-copy files
4166 in the computation of the total size and file count.
4170 g_stat ((*i).c_str(), &gsb);
4171 copied += gsb.st_size;
4174 double fraction = (double) copied / total_bytes;
4176 /* tell someone "X percent, file M of N"; M is one-based */
4178 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4179 bool keep_going = true;
4186 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4192 /* copy optional folders, if any */
4194 string old = plugins_dir ();
4195 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4196 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4197 copy_files (old, newdir);
4200 old = externals_dir ();
4201 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4202 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4203 copy_files (old, newdir);
4206 old = automation_dir ();
4207 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4208 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4209 copy_files (old, newdir);
4212 if (saveas.copy_media) {
4214 /* only needed if we are copying media, since the
4215 * analysis data refers to media data
4218 old = analysis_dir ();
4219 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4220 string newdir = Glib::build_filename (to_dir, "analysis");
4221 copy_files (old, newdir);
4227 _current_snapshot_name = saveas.new_name;
4228 _name = saveas.new_name;
4230 if (!saveas.copy_media) {
4232 /* reset search paths of the new session (which we're pretending to be right now) to
4233 include the original session search path, so we can still find all audio.
4236 if (internal_file_cnt) {
4237 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4238 ensure_search_path_includes (*s, DataType::AUDIO);
4241 for (vector<string>::iterator s = old_search_path[DataType::MIDI].begin(); s != old_search_path[DataType::MIDI].end(); ++s) {
4242 ensure_search_path_includes (*s, DataType::MIDI);
4247 bool was_dirty = dirty ();
4249 save_state ("", false, false);
4250 save_default_options ();
4252 if (saveas.copy_media && saveas.copy_external) {
4253 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4254 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4258 if (!saveas.switch_to) {
4260 /* switch back to the way things were */
4264 _current_snapshot_name = old_snapshot;
4266 (*_session_dir) = old_sd;
4272 if (internal_file_cnt) {
4273 /* reset these to their original values */
4274 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4275 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4280 /* prune session dirs, and update disk space statistics
4285 session_dirs.clear ();
4286 session_dirs.push_back (sp);
4287 refresh_disk_space ();
4289 /* ensure that all existing tracks reset their current capture source paths
4291 reset_write_sources (true, true);
4293 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4294 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4297 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4298 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4304 if (fs->within_session()) {
4305 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4306 fs->set_path (newpath);
4311 } catch (Glib::FileError& e) {
4313 saveas.failure_message = e.what();
4315 /* recursively remove all the directories */
4317 remove_directory (to_dir);
4325 saveas.failure_message = _("unknown reason");
4327 /* recursively remove all the directories */
4329 remove_directory (to_dir);