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 */
235 _tempo_map = new TempoMap (_current_frame_rate);
236 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
238 /* MidiClock requires a tempo map */
240 midi_clock = new MidiClockTicker ();
241 midi_clock->set_session (this);
243 /* crossfades require sample rate knowledge */
245 SndFileSource::setup_standard_crossfades (*this, frame_rate());
246 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
248 AudioDiskstream::allocate_working_buffers();
249 refresh_disk_space ();
251 /* we're finally ready to call set_state() ... all objects have
252 * been created, the engine is running.
256 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
260 // set_state() will call setup_raid_path(), but if it's a new session we need
261 // to call setup_raid_path() here.
262 setup_raid_path (_path);
267 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
268 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
270 Config->map_parameters (ff);
271 config.map_parameters (ft);
273 /* Reset all panners */
275 Delivery::reset_panners ();
277 /* this will cause the CPM to instantiate any protocols that are in use
278 * (or mandatory), which will pass it this Session, and then call
279 * set_state() on each instantiated protocol to match stored state.
282 ControlProtocolManager::instance().set_session (this);
284 /* This must be done after the ControlProtocolManager set_session above,
285 as it will set states for ports which the ControlProtocolManager creates.
288 // XXX set state of MIDI::Port's
289 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
291 /* And this must be done after the MIDI::Manager::set_port_states as
292 * it will try to make connections whose details are loaded by set_port_states.
297 /* Let control protocols know that we are now all connected, so they
298 * could start talking to surfaces if they want to.
301 ControlProtocolManager::instance().midi_connectivity_established ();
303 if (_is_new && !no_auto_connect()) {
304 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
305 auto_connect_master_bus ();
308 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
310 /* update latencies */
312 initialize_latencies ();
314 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
315 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
316 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
318 } catch (AudioEngine::PortRegistrationFailure& err) {
319 /* handle this one in a different way than all others, so that its clear what happened */
320 error << err.what() << endmsg;
326 BootMessage (_("Reset Remote Controls"));
328 // send_full_time_code (0);
329 _engine.transport_locate (0);
331 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
332 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
334 MIDI::Name::MidiPatchManager::instance().set_session (this);
337 /* initial program change will be delivered later; see ::config_changed() */
339 _state_of_the_state = Clean;
341 Port::set_connecting_blocked (false);
343 DirtyChanged (); /* EMIT SIGNAL */
347 } else if (state_was_pending) {
349 remove_pending_capture_state ();
350 state_was_pending = false;
357 Session::raid_path () const
359 Searchpath raid_search_path;
361 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
362 raid_search_path += (*i).path;
365 return raid_search_path.to_string ();
369 Session::setup_raid_path (string path)
378 session_dirs.clear ();
380 Searchpath search_path(path);
381 Searchpath sound_search_path;
382 Searchpath midi_search_path;
384 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
386 sp.blocks = 0; // not needed
387 session_dirs.push_back (sp);
389 SessionDirectory sdir(sp.path);
391 sound_search_path += sdir.sound_path ();
392 midi_search_path += sdir.midi_path ();
395 // reset the round-robin soundfile path thingie
396 last_rr_session_dir = session_dirs.begin();
400 Session::path_is_within_session (const std::string& path)
402 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
403 if (PBD::path_is_within (i->path, path)) {
411 Session::ensure_subdirs ()
415 dir = session_directory().peak_path();
417 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
418 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
422 dir = session_directory().sound_path();
424 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
425 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
429 dir = session_directory().midi_path();
431 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
432 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
436 dir = session_directory().dead_path();
438 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
439 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
443 dir = session_directory().export_path();
445 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
446 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
450 dir = analysis_dir ();
452 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
453 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
457 dir = plugins_dir ();
459 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
460 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
464 dir = externals_dir ();
466 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
467 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
474 /** @param session_template directory containing session template, or empty.
475 * Caller must not hold process lock.
478 Session::create (const string& session_template, BusProfile* bus_profile)
480 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
481 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
485 if (ensure_subdirs ()) {
489 _writable = exists_and_writable (_path);
491 if (!session_template.empty()) {
492 std::string in_path = session_template_dir_to_file (session_template);
494 ifstream in(in_path.c_str());
497 /* no need to call legalize_for_path() since the string
498 * in session_template is already a legal path name
500 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
502 ofstream out(out_path.c_str());
508 /* Copy plugin state files from template to new session */
509 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
510 copy_recurse (template_plugins, plugins_dir ());
515 error << string_compose (_("Could not open %1 for writing session template"), out_path)
521 error << string_compose (_("Could not open session template %1 for reading"), in_path)
528 /* set initial start + end point */
530 _state_of_the_state = Clean;
532 /* set up Master Out and Control Out if necessary */
537 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
539 if (bus_profile->master_out_channels) {
540 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
544 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
545 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
548 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
549 r->input()->ensure_io (count, false, this);
550 r->output()->ensure_io (count, false, this);
556 /* prohibit auto-connect to master, because there isn't one */
557 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
561 add_routes (rl, false, false, false);
564 /* this allows the user to override settings with an environment variable.
567 if (no_auto_connect()) {
568 bus_profile->input_ac = AutoConnectOption (0);
569 bus_profile->output_ac = AutoConnectOption (0);
572 Config->set_input_auto_connect (bus_profile->input_ac);
573 Config->set_output_auto_connect (bus_profile->output_ac);
576 if (Config->get_use_monitor_bus() && bus_profile) {
577 add_monitor_section ();
584 Session::maybe_write_autosave()
586 if (dirty() && record_status() != Recording) {
587 save_state("", true);
592 Session::remove_pending_capture_state ()
594 std::string pending_state_file_path(_session_dir->root_path());
596 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
598 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
600 if (g_remove (pending_state_file_path.c_str()) != 0) {
601 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
602 pending_state_file_path, g_strerror (errno)) << endmsg;
606 /** Rename a state file.
607 * @param old_name Old snapshot name.
608 * @param new_name New snapshot name.
611 Session::rename_state (string old_name, string new_name)
613 if (old_name == _current_snapshot_name || old_name == _name) {
614 /* refuse to rename the current snapshot or the "main" one */
618 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
619 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
621 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
622 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
624 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
625 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
626 old_name, new_name, g_strerror(errno)) << endmsg;
630 /** Remove a state file.
631 * @param snapshot_name Snapshot name.
634 Session::remove_state (string snapshot_name)
636 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
637 // refuse to remove the current snapshot or the "main" one
641 std::string xml_path(_session_dir->root_path());
643 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
645 if (!create_backup_file (xml_path)) {
646 // don't remove it if a backup can't be made
647 // create_backup_file will log the error.
652 if (g_remove (xml_path.c_str()) != 0) {
653 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
654 xml_path, g_strerror (errno)) << endmsg;
658 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
660 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
663 std::string xml_path(_session_dir->root_path());
665 /* prevent concurrent saves from different threads */
667 Glib::Threads::Mutex::Lock lm (save_state_lock);
669 if (!_writable || (_state_of_the_state & CannotSave)) {
673 if (g_atomic_int_get(&_suspend_save)) {
677 _save_queued = false;
679 if (!_engine.connected ()) {
680 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
686 /* tell sources we're saving first, in case they write out to a new file
687 * which should be saved with the state rather than the old one */
688 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
690 i->second->session_saved();
691 } catch (Evoral::SMF::FileError& e) {
692 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
696 SaveSession (); /* EMIT SIGNAL */
698 tree.set_root (&get_state());
700 if (snapshot_name.empty()) {
701 snapshot_name = _current_snapshot_name;
702 } else if (switch_to_snapshot) {
703 _current_snapshot_name = snapshot_name;
708 /* proper save: use statefile_suffix (.ardour in English) */
710 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
712 /* make a backup copy of the old file */
714 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
715 // create_backup_file will log the error
721 /* pending save: use pending_suffix (.pending in English) */
722 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
725 std::string tmp_path(_session_dir->root_path());
726 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
728 cerr << "actually writing state to " << tmp_path << endl;
730 if (!tree.write (tmp_path)) {
731 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
732 if (g_remove (tmp_path.c_str()) != 0) {
733 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
734 tmp_path, g_strerror (errno)) << endmsg;
740 cerr << "renaming state to " << xml_path << endl;
742 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
743 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
744 tmp_path, xml_path, g_strerror(errno)) << endmsg;
745 if (g_remove (tmp_path.c_str()) != 0) {
746 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
747 tmp_path, g_strerror (errno)) << endmsg;
755 save_history (snapshot_name);
757 bool was_dirty = dirty();
759 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
762 DirtyChanged (); /* EMIT SIGNAL */
765 StateSaved (snapshot_name); /* EMIT SIGNAL */
772 Session::restore_state (string snapshot_name)
774 if (load_state (snapshot_name) == 0) {
775 set_state (*state_tree->root(), Stateful::loading_state_version);
782 Session::load_state (string snapshot_name)
787 state_was_pending = false;
789 /* check for leftover pending state from a crashed capture attempt */
791 std::string xmlpath(_session_dir->root_path());
792 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
794 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
796 /* there is pending state from a crashed capture attempt */
798 boost::optional<int> r = AskAboutPendingState();
799 if (r.get_value_or (1)) {
800 state_was_pending = true;
804 if (!state_was_pending) {
805 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
808 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
809 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
810 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
811 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
816 state_tree = new XMLTree;
820 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
822 if (!state_tree->read (xmlpath)) {
823 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
829 XMLNode& root (*state_tree->root());
831 if (root.name() != X_("Session")) {
832 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
838 const XMLProperty* prop;
840 if ((prop = root.property ("version")) == 0) {
841 /* no version implies very old version of Ardour */
842 Stateful::loading_state_version = 1000;
844 if (prop->value().find ('.') != string::npos) {
845 /* old school version format */
846 if (prop->value()[0] == '2') {
847 Stateful::loading_state_version = 2000;
849 Stateful::loading_state_version = 3000;
852 Stateful::loading_state_version = atoi (prop->value());
856 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
858 std::string backup_path(_session_dir->root_path());
859 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
860 backup_path = Glib::build_filename (backup_path, backup_filename);
862 // only create a backup for a given statefile version once
864 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
866 VersionMismatch (xmlpath, backup_path);
868 if (!copy_file (xmlpath, backup_path)) {;
878 Session::load_options (const XMLNode& node)
880 LocaleGuard lg (X_("POSIX"));
881 config.set_variables (node);
886 Session::save_default_options ()
888 return config.save_state();
898 Session::get_template()
900 /* if we don't disable rec-enable, diskstreams
901 will believe they need to store their capture
902 sources in their state node.
905 disable_record (false);
911 Session::state (bool full_state)
913 XMLNode* node = new XMLNode("Session");
917 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
918 node->add_property("version", buf);
920 /* store configuration settings */
924 node->add_property ("name", _name);
925 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
926 node->add_property ("sample-rate", buf);
928 if (session_dirs.size() > 1) {
932 vector<space_and_path>::iterator i = session_dirs.begin();
933 vector<space_and_path>::iterator next;
935 ++i; /* skip the first one */
939 while (i != session_dirs.end()) {
943 if (next != session_dirs.end()) {
944 p += G_SEARCHPATH_SEPARATOR;
953 child = node->add_child ("Path");
954 child->add_content (p);
958 /* save the ID counter */
960 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
961 node->add_property ("id-counter", buf);
963 /* save the event ID counter */
965 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
966 node->add_property ("event-counter", buf);
968 /* various options */
970 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
971 if (!midi_port_nodes.empty()) {
972 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
973 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
974 midi_port_stuff->add_child_nocopy (**n);
976 node->add_child_nocopy (*midi_port_stuff);
979 node->add_child_nocopy (config.get_variables ());
981 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
983 child = node->add_child ("Sources");
986 Glib::Threads::Mutex::Lock sl (source_lock);
988 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
990 /* Don't save information about non-file Sources, or
991 * about non-destructive file sources that are empty
992 * and unused by any regions.
995 boost::shared_ptr<FileSource> fs;
997 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
999 if (!fs->destructive()) {
1000 if (fs->empty() && !fs->used()) {
1005 child->add_child_nocopy (siter->second->get_state());
1010 child = node->add_child ("Regions");
1013 Glib::Threads::Mutex::Lock rl (region_lock);
1014 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1015 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1016 boost::shared_ptr<Region> r = i->second;
1017 /* only store regions not attached to playlists */
1018 if (r->playlist() == 0) {
1019 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1020 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1022 child->add_child_nocopy (r->get_state ());
1027 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1029 if (!cassocs.empty()) {
1030 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1032 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1034 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1035 i->first->id().print (buf, sizeof (buf));
1036 can->add_property (X_("copy"), buf);
1037 i->second->id().print (buf, sizeof (buf));
1038 can->add_property (X_("original"), buf);
1039 ca->add_child_nocopy (*can);
1045 node->add_child_nocopy (_locations->get_state());
1047 // for a template, just create a new Locations, populate it
1048 // with the default start and end, and get the state for that.
1049 Locations loc (*this);
1050 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1051 range->set (max_framepos, 0);
1053 node->add_child_nocopy (loc.get_state());
1056 child = node->add_child ("Bundles");
1058 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1059 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1060 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1062 child->add_child_nocopy (b->get_state());
1067 child = node->add_child ("Routes");
1069 boost::shared_ptr<RouteList> r = routes.reader ();
1071 RoutePublicOrderSorter cmp;
1072 RouteList public_order (*r);
1073 public_order.sort (cmp);
1075 /* the sort should have put control outs first */
1078 assert (_monitor_out == public_order.front());
1081 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1082 if (!(*i)->is_auditioner()) {
1084 child->add_child_nocopy ((*i)->get_state());
1086 child->add_child_nocopy ((*i)->get_template());
1092 playlists->add_state (node, full_state);
1094 child = node->add_child ("RouteGroups");
1095 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1096 child->add_child_nocopy ((*i)->get_state());
1100 XMLNode* gain_child = node->add_child ("Click");
1101 gain_child->add_child_nocopy (_click_io->state (full_state));
1102 gain_child->add_child_nocopy (_click_gain->state (full_state));
1106 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1107 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1111 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1112 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1115 node->add_child_nocopy (_speakers->get_state());
1116 node->add_child_nocopy (_tempo_map->get_state());
1117 node->add_child_nocopy (get_control_protocol_state());
1120 node->add_child_copy (*_extra_xml);
1127 Session::get_control_protocol_state ()
1129 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1130 return cpm.get_state();
1134 Session::set_state (const XMLNode& node, int version)
1138 const XMLProperty* prop;
1141 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1143 if (node.name() != X_("Session")) {
1144 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1148 if ((prop = node.property ("name")) != 0) {
1149 _name = prop->value ();
1152 if ((prop = node.property (X_("sample-rate"))) != 0) {
1154 _nominal_frame_rate = atoi (prop->value());
1156 if (_nominal_frame_rate != _current_frame_rate) {
1157 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1158 if (r.get_value_or (0)) {
1164 setup_raid_path(_session_dir->root_path());
1166 if ((prop = node.property (X_("id-counter"))) != 0) {
1168 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1169 ID::init_counter (x);
1171 /* old sessions used a timebased counter, so fake
1172 the startup ID counter based on a standard
1177 ID::init_counter (now);
1180 if ((prop = node.property (X_("event-counter"))) != 0) {
1181 Evoral::init_event_id_counter (atoi (prop->value()));
1185 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1186 _midi_ports->set_midi_port_states (child->children());
1189 IO::disable_connecting ();
1191 Stateful::save_extra_xml (node);
1193 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1194 load_options (*child);
1195 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1196 load_options (*child);
1198 error << _("Session: XML state has no options section") << endmsg;
1201 if (version >= 3000) {
1202 if ((child = find_named_node (node, "Metadata")) == 0) {
1203 warning << _("Session: XML state has no metadata section") << endmsg;
1204 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1209 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1210 _speakers->set_state (*child, version);
1213 if ((child = find_named_node (node, "Sources")) == 0) {
1214 error << _("Session: XML state has no sources section") << endmsg;
1216 } else if (load_sources (*child)) {
1220 if ((child = find_named_node (node, "TempoMap")) == 0) {
1221 error << _("Session: XML state has no Tempo Map section") << endmsg;
1223 } else if (_tempo_map->set_state (*child, version)) {
1227 if ((child = find_named_node (node, "Locations")) == 0) {
1228 error << _("Session: XML state has no locations section") << endmsg;
1230 } else if (_locations->set_state (*child, version)) {
1234 locations_changed ();
1236 if (_session_range_location) {
1237 AudioFileSource::set_header_position_offset (_session_range_location->start());
1240 if ((child = find_named_node (node, "Regions")) == 0) {
1241 error << _("Session: XML state has no Regions section") << endmsg;
1243 } else if (load_regions (*child)) {
1247 if ((child = find_named_node (node, "Playlists")) == 0) {
1248 error << _("Session: XML state has no playlists section") << endmsg;
1250 } else if (playlists->load (*this, *child)) {
1254 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1256 } else if (playlists->load_unused (*this, *child)) {
1260 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1261 if (load_compounds (*child)) {
1266 if (version >= 3000) {
1267 if ((child = find_named_node (node, "Bundles")) == 0) {
1268 warning << _("Session: XML state has no bundles section") << endmsg;
1271 /* We can't load Bundles yet as they need to be able
1272 to convert from port names to Port objects, which can't happen until
1274 _bundle_xml_node = new XMLNode (*child);
1278 if (version < 3000) {
1279 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1280 error << _("Session: XML state has no diskstreams section") << endmsg;
1282 } else if (load_diskstreams_2X (*child, version)) {
1287 if ((child = find_named_node (node, "Routes")) == 0) {
1288 error << _("Session: XML state has no routes section") << endmsg;
1290 } else if (load_routes (*child, version)) {
1294 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1295 _diskstreams_2X.clear ();
1297 if (version >= 3000) {
1299 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1300 error << _("Session: XML state has no route groups section") << endmsg;
1302 } else if (load_route_groups (*child, version)) {
1306 } else if (version < 3000) {
1308 if ((child = find_named_node (node, "EditGroups")) == 0) {
1309 error << _("Session: XML state has no edit groups section") << endmsg;
1311 } else if (load_route_groups (*child, version)) {
1315 if ((child = find_named_node (node, "MixGroups")) == 0) {
1316 error << _("Session: XML state has no mix groups section") << endmsg;
1318 } else if (load_route_groups (*child, version)) {
1323 if ((child = find_named_node (node, "Click")) == 0) {
1324 warning << _("Session: XML state has no click section") << endmsg;
1325 } else if (_click_io) {
1326 setup_click_state (&node);
1329 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1330 ControlProtocolManager::instance().set_state (*child, version);
1333 update_have_rec_enabled_track ();
1335 /* here beginneth the second phase ... */
1337 StateReady (); /* EMIT SIGNAL */
1350 Session::load_routes (const XMLNode& node, int version)
1353 XMLNodeConstIterator niter;
1354 RouteList new_routes;
1356 nlist = node.children();
1360 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1362 boost::shared_ptr<Route> route;
1363 if (version < 3000) {
1364 route = XMLRouteFactory_2X (**niter, version);
1366 route = XMLRouteFactory (**niter, version);
1370 error << _("Session: cannot create Route from XML description.") << endmsg;
1374 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1376 new_routes.push_back (route);
1379 add_routes (new_routes, false, false, false);
1384 boost::shared_ptr<Route>
1385 Session::XMLRouteFactory (const XMLNode& node, int version)
1387 boost::shared_ptr<Route> ret;
1389 if (node.name() != "Route") {
1393 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1395 DataType type = DataType::AUDIO;
1396 const XMLProperty* prop = node.property("default-type");
1399 type = DataType (prop->value());
1402 assert (type != DataType::NIL);
1406 boost::shared_ptr<Track> track;
1408 if (type == DataType::AUDIO) {
1409 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1411 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1414 if (track->init()) {
1418 if (track->set_state (node, version)) {
1422 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1423 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1428 enum Route::Flag flags = Route::Flag(0);
1429 const XMLProperty* prop = node.property("flags");
1431 flags = Route::Flag (string_2_enum (prop->value(), flags));
1434 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1436 if (r->init () == 0 && r->set_state (node, version) == 0) {
1437 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1438 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1447 boost::shared_ptr<Route>
1448 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1450 boost::shared_ptr<Route> ret;
1452 if (node.name() != "Route") {
1456 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1458 ds_prop = node.property (X_("diskstream"));
1461 DataType type = DataType::AUDIO;
1462 const XMLProperty* prop = node.property("default-type");
1465 type = DataType (prop->value());
1468 assert (type != DataType::NIL);
1472 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1473 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1477 if (i == _diskstreams_2X.end()) {
1478 error << _("Could not find diskstream for route") << endmsg;
1479 return boost::shared_ptr<Route> ();
1482 boost::shared_ptr<Track> track;
1484 if (type == DataType::AUDIO) {
1485 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1487 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1490 if (track->init()) {
1494 if (track->set_state (node, version)) {
1498 track->set_diskstream (*i);
1500 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1501 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1506 enum Route::Flag flags = Route::Flag(0);
1507 const XMLProperty* prop = node.property("flags");
1509 flags = Route::Flag (string_2_enum (prop->value(), flags));
1512 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1514 if (r->init () == 0 && r->set_state (node, version) == 0) {
1515 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1516 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1526 Session::load_regions (const XMLNode& node)
1529 XMLNodeConstIterator niter;
1530 boost::shared_ptr<Region> region;
1532 nlist = node.children();
1536 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1537 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1538 error << _("Session: cannot create Region from XML description.");
1539 const XMLProperty *name = (**niter).property("name");
1542 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1553 Session::load_compounds (const XMLNode& node)
1555 XMLNodeList calist = node.children();
1556 XMLNodeConstIterator caiter;
1557 XMLProperty *caprop;
1559 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1560 XMLNode* ca = *caiter;
1564 if ((caprop = ca->property (X_("original"))) == 0) {
1567 orig_id = caprop->value();
1569 if ((caprop = ca->property (X_("copy"))) == 0) {
1572 copy_id = caprop->value();
1574 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1575 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1577 if (!orig || !copy) {
1578 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1584 RegionFactory::add_compound_association (orig, copy);
1591 Session::load_nested_sources (const XMLNode& node)
1594 XMLNodeConstIterator niter;
1596 nlist = node.children();
1598 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1599 if ((*niter)->name() == "Source") {
1601 /* it may already exist, so don't recreate it unnecessarily
1604 XMLProperty* prop = (*niter)->property (X_("id"));
1606 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1610 ID source_id (prop->value());
1612 if (!source_by_id (source_id)) {
1615 SourceFactory::create (*this, **niter, true);
1617 catch (failed_constructor& err) {
1618 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1625 boost::shared_ptr<Region>
1626 Session::XMLRegionFactory (const XMLNode& node, bool full)
1628 const XMLProperty* type = node.property("type");
1632 const XMLNodeList& nlist = node.children();
1634 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1635 XMLNode *child = (*niter);
1636 if (child->name() == "NestedSource") {
1637 load_nested_sources (*child);
1641 if (!type || type->value() == "audio") {
1642 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1643 } else if (type->value() == "midi") {
1644 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1647 } catch (failed_constructor& err) {
1648 return boost::shared_ptr<Region> ();
1651 return boost::shared_ptr<Region> ();
1654 boost::shared_ptr<AudioRegion>
1655 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1657 const XMLProperty* prop;
1658 boost::shared_ptr<Source> source;
1659 boost::shared_ptr<AudioSource> as;
1661 SourceList master_sources;
1662 uint32_t nchans = 1;
1665 if (node.name() != X_("Region")) {
1666 return boost::shared_ptr<AudioRegion>();
1669 if ((prop = node.property (X_("channels"))) != 0) {
1670 nchans = atoi (prop->value().c_str());
1673 if ((prop = node.property ("name")) == 0) {
1674 cerr << "no name for this region\n";
1678 if ((prop = node.property (X_("source-0"))) == 0) {
1679 if ((prop = node.property ("source")) == 0) {
1680 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1681 return boost::shared_ptr<AudioRegion>();
1685 PBD::ID s_id (prop->value());
1687 if ((source = source_by_id (s_id)) == 0) {
1688 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1689 return boost::shared_ptr<AudioRegion>();
1692 as = boost::dynamic_pointer_cast<AudioSource>(source);
1694 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1695 return boost::shared_ptr<AudioRegion>();
1698 sources.push_back (as);
1700 /* pickup other channels */
1702 for (uint32_t n=1; n < nchans; ++n) {
1703 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1704 if ((prop = node.property (buf)) != 0) {
1706 PBD::ID id2 (prop->value());
1708 if ((source = source_by_id (id2)) == 0) {
1709 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1710 return boost::shared_ptr<AudioRegion>();
1713 as = boost::dynamic_pointer_cast<AudioSource>(source);
1715 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1716 return boost::shared_ptr<AudioRegion>();
1718 sources.push_back (as);
1722 for (uint32_t n = 0; n < nchans; ++n) {
1723 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1724 if ((prop = node.property (buf)) != 0) {
1726 PBD::ID id2 (prop->value());
1728 if ((source = source_by_id (id2)) == 0) {
1729 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1730 return boost::shared_ptr<AudioRegion>();
1733 as = boost::dynamic_pointer_cast<AudioSource>(source);
1735 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1736 return boost::shared_ptr<AudioRegion>();
1738 master_sources.push_back (as);
1743 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1745 /* a final detail: this is the one and only place that we know how long missing files are */
1747 if (region->whole_file()) {
1748 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1749 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1751 sfp->set_length (region->length());
1756 if (!master_sources.empty()) {
1757 if (master_sources.size() != nchans) {
1758 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1760 region->set_master_sources (master_sources);
1768 catch (failed_constructor& err) {
1769 return boost::shared_ptr<AudioRegion>();
1773 boost::shared_ptr<MidiRegion>
1774 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1776 const XMLProperty* prop;
1777 boost::shared_ptr<Source> source;
1778 boost::shared_ptr<MidiSource> ms;
1781 if (node.name() != X_("Region")) {
1782 return boost::shared_ptr<MidiRegion>();
1785 if ((prop = node.property ("name")) == 0) {
1786 cerr << "no name for this region\n";
1790 if ((prop = node.property (X_("source-0"))) == 0) {
1791 if ((prop = node.property ("source")) == 0) {
1792 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1793 return boost::shared_ptr<MidiRegion>();
1797 PBD::ID s_id (prop->value());
1799 if ((source = source_by_id (s_id)) == 0) {
1800 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1801 return boost::shared_ptr<MidiRegion>();
1804 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1806 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1807 return boost::shared_ptr<MidiRegion>();
1810 sources.push_back (ms);
1813 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1814 /* a final detail: this is the one and only place that we know how long missing files are */
1816 if (region->whole_file()) {
1817 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1818 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1820 sfp->set_length (region->length());
1828 catch (failed_constructor& err) {
1829 return boost::shared_ptr<MidiRegion>();
1834 Session::get_sources_as_xml ()
1837 XMLNode* node = new XMLNode (X_("Sources"));
1838 Glib::Threads::Mutex::Lock lm (source_lock);
1840 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1841 node->add_child_nocopy (i->second->get_state());
1848 Session::load_sources (const XMLNode& node)
1851 XMLNodeConstIterator niter;
1852 boost::shared_ptr<Source> source; /* don't need this but it stops some
1853 * versions of gcc complaining about
1854 * discarded return values.
1857 nlist = node.children();
1861 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1864 if ((source = XMLSourceFactory (**niter)) == 0) {
1865 error << _("Session: cannot create Source from XML description.") << endmsg;
1868 } catch (MissingSource& err) {
1872 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1873 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1874 PROGRAM_NAME) << endmsg;
1878 if (!no_questions_about_missing_files) {
1879 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1884 switch (user_choice) {
1886 /* user added a new search location, so try again */
1891 /* user asked to quit the entire session load
1896 no_questions_about_missing_files = true;
1900 no_questions_about_missing_files = true;
1907 case DataType::AUDIO:
1908 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1911 case DataType::MIDI:
1912 /* The MIDI file is actually missing so
1913 * just create a new one in the same
1914 * location. Do not announce its
1918 if (!Glib::path_is_absolute (err.path)) {
1919 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
1921 /* this should be an unrecoverable error: we would be creating a MIDI file outside
1926 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
1927 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
1928 /* reset ID to match the missing one */
1929 source->set_id (**niter);
1930 /* Now we can announce it */
1931 SourceFactory::SourceCreated (source);
1942 boost::shared_ptr<Source>
1943 Session::XMLSourceFactory (const XMLNode& node)
1945 if (node.name() != "Source") {
1946 return boost::shared_ptr<Source>();
1950 /* note: do peak building in another thread when loading session state */
1951 return SourceFactory::create (*this, node, true);
1954 catch (failed_constructor& err) {
1955 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
1956 return boost::shared_ptr<Source>();
1961 Session::save_template (string template_name)
1965 if (_state_of_the_state & CannotSave) {
1969 std::string user_template_dir(user_template_directory());
1971 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
1972 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
1973 user_template_dir, g_strerror (errno)) << endmsg;
1977 tree.set_root (&get_template());
1979 std::string template_dir_path(user_template_dir);
1981 /* directory to put the template in */
1982 template_dir_path = Glib::build_filename (template_dir_path, template_name);
1984 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
1985 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
1986 template_dir_path) << endmsg;
1990 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
1991 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
1992 template_dir_path, g_strerror (errno)) << endmsg;
1997 std::string template_file_path(template_dir_path);
1998 template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
2000 if (!tree.write (template_file_path)) {
2001 error << _("template not saved") << endmsg;
2005 /* copy plugin state directory */
2007 std::string template_plugin_state_path(template_dir_path);
2008 template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
2010 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2011 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2012 template_plugin_state_path, g_strerror (errno)) << endmsg;
2016 copy_recurse (plugins_dir(), template_plugin_state_path);
2022 Session::refresh_disk_space ()
2024 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2026 Glib::Threads::Mutex::Lock lm (space_lock);
2028 /* get freespace on every FS that is part of the session path */
2030 _total_free_4k_blocks = 0;
2031 _total_free_4k_blocks_uncertain = false;
2033 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2035 struct statfs statfsbuf;
2036 statfs (i->path.c_str(), &statfsbuf);
2038 double const scale = statfsbuf.f_bsize / 4096.0;
2040 /* See if this filesystem is read-only */
2041 struct statvfs statvfsbuf;
2042 statvfs (i->path.c_str(), &statvfsbuf);
2044 /* f_bavail can be 0 if it is undefined for whatever
2045 filesystem we are looking at; Samba shares mounted
2046 via GVFS are an example of this.
2048 if (statfsbuf.f_bavail == 0) {
2049 /* block count unknown */
2051 i->blocks_unknown = true;
2052 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2053 /* read-only filesystem */
2055 i->blocks_unknown = false;
2057 /* read/write filesystem with known space */
2058 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2059 i->blocks_unknown = false;
2062 _total_free_4k_blocks += i->blocks;
2063 if (i->blocks_unknown) {
2064 _total_free_4k_blocks_uncertain = true;
2067 #elif defined (COMPILER_MSVC)
2068 vector<string> scanned_volumes;
2069 vector<string>::iterator j;
2070 vector<space_and_path>::iterator i;
2071 DWORD nSectorsPerCluster, nBytesPerSector,
2072 nFreeClusters, nTotalClusters;
2076 _total_free_4k_blocks = 0;
2078 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2079 strncpy (disk_drive, (*i).path.c_str(), 3);
2083 volume_found = false;
2084 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2086 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2087 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2088 i->blocks = (uint32_t)(nFreeBytes / 4096);
2090 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2091 if (0 == j->compare(disk_drive)) {
2092 volume_found = true;
2097 if (!volume_found) {
2098 scanned_volumes.push_back(disk_drive);
2099 _total_free_4k_blocks += i->blocks;
2104 if (0 == _total_free_4k_blocks) {
2105 strncpy (disk_drive, path().c_str(), 3);
2108 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2110 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2111 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2112 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2119 Session::get_best_session_directory_for_new_audio ()
2121 vector<space_and_path>::iterator i;
2122 string result = _session_dir->root_path();
2124 /* handle common case without system calls */
2126 if (session_dirs.size() == 1) {
2130 /* OK, here's the algorithm we're following here:
2132 We want to select which directory to use for
2133 the next file source to be created. Ideally,
2134 we'd like to use a round-robin process so as to
2135 get maximum performance benefits from splitting
2136 the files across multiple disks.
2138 However, in situations without much diskspace, an
2139 RR approach may end up filling up a filesystem
2140 with new files while others still have space.
2141 Its therefore important to pay some attention to
2142 the freespace in the filesystem holding each
2143 directory as well. However, if we did that by
2144 itself, we'd keep creating new files in the file
2145 system with the most space until it was as full
2146 as all others, thus negating any performance
2147 benefits of this RAID-1 like approach.
2149 So, we use a user-configurable space threshold. If
2150 there are at least 2 filesystems with more than this
2151 much space available, we use RR selection between them.
2152 If not, then we pick the filesystem with the most space.
2154 This gets a good balance between the two
2158 refresh_disk_space ();
2160 int free_enough = 0;
2162 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2163 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2168 if (free_enough >= 2) {
2169 /* use RR selection process, ensuring that the one
2173 i = last_rr_session_dir;
2176 if (++i == session_dirs.end()) {
2177 i = session_dirs.begin();
2180 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2181 SessionDirectory sdir(i->path);
2182 if (sdir.create ()) {
2184 last_rr_session_dir = i;
2189 } while (i != last_rr_session_dir);
2193 /* pick FS with the most freespace (and that
2194 seems to actually work ...)
2197 vector<space_and_path> sorted;
2198 space_and_path_ascending_cmp cmp;
2200 sorted = session_dirs;
2201 sort (sorted.begin(), sorted.end(), cmp);
2203 for (i = sorted.begin(); i != sorted.end(); ++i) {
2204 SessionDirectory sdir(i->path);
2205 if (sdir.create ()) {
2207 last_rr_session_dir = i;
2217 Session::automation_dir () const
2219 return Glib::build_filename (_path, "automation");
2223 Session::analysis_dir () const
2225 return Glib::build_filename (_path, "analysis");
2229 Session::plugins_dir () const
2231 return Glib::build_filename (_path, "plugins");
2235 Session::externals_dir () const
2237 return Glib::build_filename (_path, "externals");
2241 Session::load_bundles (XMLNode const & node)
2243 XMLNodeList nlist = node.children();
2244 XMLNodeConstIterator niter;
2248 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2249 if ((*niter)->name() == "InputBundle") {
2250 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2251 } else if ((*niter)->name() == "OutputBundle") {
2252 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2254 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2263 Session::load_route_groups (const XMLNode& node, int version)
2265 XMLNodeList nlist = node.children();
2266 XMLNodeConstIterator niter;
2270 if (version >= 3000) {
2272 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2273 if ((*niter)->name() == "RouteGroup") {
2274 RouteGroup* rg = new RouteGroup (*this, "");
2275 add_route_group (rg);
2276 rg->set_state (**niter, version);
2280 } else if (version < 3000) {
2282 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2283 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2284 RouteGroup* rg = new RouteGroup (*this, "");
2285 add_route_group (rg);
2286 rg->set_state (**niter, version);
2295 state_file_filter (const string &str, void* /*arg*/)
2297 return (str.length() > strlen(statefile_suffix) &&
2298 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2302 remove_end(string state)
2304 string statename(state);
2306 string::size_type start,end;
2307 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2308 statename = statename.substr (start+1);
2311 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2312 end = statename.length();
2315 return string(statename.substr (0, end));
2319 Session::possible_states (string path)
2321 vector<string> states;
2322 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2324 transform(states.begin(), states.end(), states.begin(), remove_end);
2326 sort (states.begin(), states.end());
2332 Session::possible_states () const
2334 return possible_states(_path);
2338 Session::add_route_group (RouteGroup* g)
2340 _route_groups.push_back (g);
2341 route_group_added (g); /* EMIT SIGNAL */
2343 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2344 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2345 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2351 Session::remove_route_group (RouteGroup& rg)
2353 list<RouteGroup*>::iterator i;
2355 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2356 _route_groups.erase (i);
2359 route_group_removed (); /* EMIT SIGNAL */
2363 /** Set a new order for our route groups, without adding or removing any.
2364 * @param groups Route group list in the new order.
2367 Session::reorder_route_groups (list<RouteGroup*> groups)
2369 _route_groups = groups;
2371 route_groups_reordered (); /* EMIT SIGNAL */
2377 Session::route_group_by_name (string name)
2379 list<RouteGroup *>::iterator i;
2381 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2382 if ((*i)->name() == name) {
2390 Session::all_route_group() const
2392 return *_all_route_group;
2396 Session::add_commands (vector<Command*> const & cmds)
2398 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2404 Session::begin_reversible_command (const string& name)
2406 begin_reversible_command (g_quark_from_string (name.c_str ()));
2409 /** Begin a reversible command using a GQuark to identify it.
2410 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2411 * but there must be as many begin...()s as there are commit...()s.
2414 Session::begin_reversible_command (GQuark q)
2416 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2417 to hold all the commands that are committed. This keeps the order of
2418 commands correct in the history.
2421 if (_current_trans == 0) {
2422 /* start a new transaction */
2423 assert (_current_trans_quarks.empty ());
2424 _current_trans = new UndoTransaction();
2425 _current_trans->set_name (g_quark_to_string (q));
2428 _current_trans_quarks.push_front (q);
2432 Session::commit_reversible_command (Command *cmd)
2434 assert (_current_trans);
2435 assert (!_current_trans_quarks.empty ());
2440 _current_trans->add_command (cmd);
2443 _current_trans_quarks.pop_front ();
2445 if (!_current_trans_quarks.empty ()) {
2446 /* the transaction we're committing is not the top-level one */
2450 if (_current_trans->empty()) {
2451 /* no commands were added to the transaction, so just get rid of it */
2452 delete _current_trans;
2457 gettimeofday (&now, 0);
2458 _current_trans->set_timestamp (now);
2460 _history.add (_current_trans);
2465 accept_all_audio_files (const string& path, void* /*arg*/)
2467 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2471 if (!AudioFileSource::safe_audio_file_extension (path)) {
2479 accept_all_midi_files (const string& path, void* /*arg*/)
2481 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2485 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2486 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2487 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2491 accept_all_state_files (const string& path, void* /*arg*/)
2493 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2497 std::string const statefile_ext (statefile_suffix);
2498 if (path.length() >= statefile_ext.length()) {
2499 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2506 Session::find_all_sources (string path, set<string>& result)
2511 if (!tree.read (path)) {
2515 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2520 XMLNodeConstIterator niter;
2522 nlist = node->children();
2526 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2530 if ((prop = (*niter)->property (X_("type"))) == 0) {
2534 DataType type (prop->value());
2536 if ((prop = (*niter)->property (X_("name"))) == 0) {
2540 if (Glib::path_is_absolute (prop->value())) {
2541 /* external file, ignore */
2549 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2550 result.insert (found_path);
2558 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2560 vector<string> state_files;
2562 string this_snapshot_path;
2568 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2569 ripped = ripped.substr (0, ripped.length() - 1);
2572 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2574 if (state_files.empty()) {
2579 this_snapshot_path = _path;
2580 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2581 this_snapshot_path += statefile_suffix;
2583 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2585 if (exclude_this_snapshot && *i == this_snapshot_path) {
2589 if (find_all_sources (*i, result) < 0) {
2597 struct RegionCounter {
2598 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2599 AudioSourceList::iterator iter;
2600 boost::shared_ptr<Region> region;
2603 RegionCounter() : count (0) {}
2607 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2609 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2610 return r.get_value_or (1);
2614 Session::cleanup_regions ()
2616 bool removed = false;
2617 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2619 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2621 uint32_t used = playlists->region_use_count (i->second);
2623 if (used == 0 && !i->second->automatic ()) {
2625 RegionFactory::map_remove (i->second);
2630 // re-check to remove parent references of compound regions
2631 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2632 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2635 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2636 if (0 == playlists->region_use_count (i->second)) {
2637 RegionFactory::map_remove (i->second);
2642 /* dump the history list */
2649 Session::cleanup_sources (CleanupReport& rep)
2651 // FIXME: needs adaptation to midi
2653 vector<boost::shared_ptr<Source> > dead_sources;
2656 vector<string> candidates;
2657 vector<string> unused;
2658 set<string> all_sources;
2667 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2669 /* consider deleting all unused playlists */
2671 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2676 /* sync the "all regions" property of each playlist with its current state
2679 playlists->sync_all_regions_with_regions ();
2681 /* find all un-used sources */
2686 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2688 SourceMap::iterator tmp;
2693 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2697 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2698 dead_sources.push_back (i->second);
2699 i->second->drop_references ();
2705 /* build a list of all the possible audio directories for the session */
2707 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2708 SessionDirectory sdir ((*i).path);
2709 asp += sdir.sound_path();
2711 audio_path += asp.to_string();
2714 /* build a list of all the possible midi directories for the session */
2716 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2717 SessionDirectory sdir ((*i).path);
2718 msp += sdir.midi_path();
2720 midi_path += msp.to_string();
2722 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2723 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2725 /* find all sources, but don't use this snapshot because the
2726 state file on disk still references sources we may have already
2730 find_all_sources_across_snapshots (all_sources, true);
2732 /* add our current source list
2735 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2736 boost::shared_ptr<FileSource> fs;
2737 SourceMap::iterator tmp = i;
2740 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2742 if (!fs->is_stub()) {
2744 if (playlists->source_use_count (fs) != 0) {
2745 all_sources.insert (fs->path());
2748 /* we might not remove this source from disk, because it may be used
2749 by other snapshots, but its not being used in this version
2750 so lets get rid of it now, along with any representative regions
2754 RegionFactory::remove_regions_using_source (i->second);
2763 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2768 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2770 tmppath1 = canonical_path (spath);
2771 tmppath2 = canonical_path ((*i));
2773 if (tmppath1 == tmppath2) {
2780 unused.push_back (spath);
2784 /* now try to move all unused files into the "dead" directory(ies) */
2786 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2787 struct stat statbuf;
2791 /* don't move the file across filesystems, just
2792 stick it in the `dead_dir_name' directory
2793 on whichever filesystem it was already on.
2796 if ((*x).find ("/sounds/") != string::npos) {
2798 /* old school, go up 1 level */
2800 newpath = Glib::path_get_dirname (*x); // "sounds"
2801 newpath = Glib::path_get_dirname (newpath); // "session-name"
2805 /* new school, go up 4 levels */
2807 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2808 newpath = Glib::path_get_dirname (newpath); // "session-name"
2809 newpath = Glib::path_get_dirname (newpath); // "interchange"
2810 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2813 newpath = Glib::build_filename (newpath, dead_dir_name);
2815 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2816 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2820 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2822 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2824 /* the new path already exists, try versioning */
2826 char buf[PATH_MAX+1];
2830 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2833 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2834 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2838 if (version == 999) {
2839 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2843 newpath = newpath_v;
2848 /* it doesn't exist, or we can't read it or something */
2852 stat ((*x).c_str(), &statbuf);
2854 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2855 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2856 (*x), newpath, strerror (errno))
2861 /* see if there an easy to find peakfile for this file, and remove it.
2864 string base = basename_nosuffix (*x);
2865 base += "%A"; /* this is what we add for the channel suffix of all native files,
2866 or for the first channel of embedded files. it will miss
2867 some peakfiles for other channels
2869 string peakpath = peak_path (base);
2871 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2872 if (::g_unlink (peakpath.c_str()) != 0) {
2873 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2874 peakpath, _path, strerror (errno))
2876 /* try to back out */
2877 ::rename (newpath.c_str(), _path.c_str());
2882 rep.paths.push_back (*x);
2883 rep.space += statbuf.st_size;
2886 /* dump the history list */
2890 /* save state so we don't end up a session file
2891 referring to non-existent sources.
2898 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2904 Session::cleanup_trash_sources (CleanupReport& rep)
2906 // FIXME: needs adaptation for MIDI
2908 vector<space_and_path>::iterator i;
2914 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2916 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2918 clear_directory (dead_dir, &rep.space, &rep.paths);
2925 Session::set_dirty ()
2927 /* never mark session dirty during loading */
2929 if (_state_of_the_state & Loading) {
2933 bool was_dirty = dirty();
2935 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2939 DirtyChanged(); /* EMIT SIGNAL */
2945 Session::set_clean ()
2947 bool was_dirty = dirty();
2949 _state_of_the_state = Clean;
2953 DirtyChanged(); /* EMIT SIGNAL */
2958 Session::set_deletion_in_progress ()
2960 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2964 Session::clear_deletion_in_progress ()
2966 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2970 Session::add_controllable (boost::shared_ptr<Controllable> c)
2972 /* this adds a controllable to the list managed by the Session.
2973 this is a subset of those managed by the Controllable class
2974 itself, and represents the only ones whose state will be saved
2975 as part of the session.
2978 Glib::Threads::Mutex::Lock lm (controllables_lock);
2979 controllables.insert (c);
2982 struct null_deleter { void operator()(void const *) const {} };
2985 Session::remove_controllable (Controllable* c)
2987 if (_state_of_the_state & Deletion) {
2991 Glib::Threads::Mutex::Lock lm (controllables_lock);
2993 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
2995 if (x != controllables.end()) {
2996 controllables.erase (x);
3000 boost::shared_ptr<Controllable>
3001 Session::controllable_by_id (const PBD::ID& id)
3003 Glib::Threads::Mutex::Lock lm (controllables_lock);
3005 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3006 if ((*i)->id() == id) {
3011 return boost::shared_ptr<Controllable>();
3014 boost::shared_ptr<Controllable>
3015 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3017 boost::shared_ptr<Controllable> c;
3018 boost::shared_ptr<Route> r;
3020 switch (desc.top_level_type()) {
3021 case ControllableDescriptor::NamedRoute:
3023 std::string str = desc.top_level_name();
3024 if (str == "Master" || str == "master") {
3026 } else if (str == "control" || str == "listen") {
3029 r = route_by_name (desc.top_level_name());
3034 case ControllableDescriptor::RemoteControlID:
3035 r = route_by_remote_id (desc.rid());
3043 switch (desc.subtype()) {
3044 case ControllableDescriptor::Gain:
3045 c = r->gain_control ();
3048 case ControllableDescriptor::Solo:
3049 c = r->solo_control();
3052 case ControllableDescriptor::Mute:
3053 c = r->mute_control();
3056 case ControllableDescriptor::Recenable:
3058 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3061 c = t->rec_enable_control ();
3066 case ControllableDescriptor::PanDirection:
3068 c = r->pannable()->pan_azimuth_control;
3072 case ControllableDescriptor::PanWidth:
3074 c = r->pannable()->pan_width_control;
3078 case ControllableDescriptor::PanElevation:
3080 c = r->pannable()->pan_elevation_control;
3084 case ControllableDescriptor::Balance:
3085 /* XXX simple pan control */
3088 case ControllableDescriptor::PluginParameter:
3090 uint32_t plugin = desc.target (0);
3091 uint32_t parameter_index = desc.target (1);
3093 /* revert to zero based counting */
3099 if (parameter_index > 0) {
3103 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3106 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3107 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3112 case ControllableDescriptor::SendGain:
3114 uint32_t send = desc.target (0);
3116 /* revert to zero-based counting */
3122 boost::shared_ptr<Processor> p = r->nth_send (send);
3125 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3126 boost::shared_ptr<Amp> a = s->amp();
3129 c = s->amp()->gain_control();
3136 /* relax and return a null pointer */
3144 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3147 Stateful::add_instant_xml (node, _path);
3150 if (write_to_config) {
3151 Config->add_instant_xml (node);
3156 Session::instant_xml (const string& node_name)
3158 return Stateful::instant_xml (node_name, _path);
3162 Session::save_history (string snapshot_name)
3170 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3171 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3175 if (snapshot_name.empty()) {
3176 snapshot_name = _current_snapshot_name;
3179 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3180 const string backup_filename = history_filename + backup_suffix;
3181 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3182 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3184 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3185 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3186 error << _("could not backup old history file, current history not saved") << endmsg;
3191 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3193 if (!tree.write (xml_path))
3195 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3197 if (g_remove (xml_path.c_str()) != 0) {
3198 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3199 xml_path, g_strerror (errno)) << endmsg;
3201 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3202 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3203 backup_path, g_strerror (errno)) << endmsg;
3213 Session::restore_history (string snapshot_name)
3217 if (snapshot_name.empty()) {
3218 snapshot_name = _current_snapshot_name;
3221 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3222 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3224 info << "Loading history from " << xml_path << endmsg;
3226 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3227 info << string_compose (_("%1: no history file \"%2\" for this session."),
3228 _name, xml_path) << endmsg;
3232 if (!tree.read (xml_path)) {
3233 error << string_compose (_("Could not understand session history file \"%1\""),
3234 xml_path) << endmsg;
3241 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3244 UndoTransaction* ut = new UndoTransaction ();
3247 ut->set_name(t->property("name")->value());
3248 stringstream ss(t->property("tv-sec")->value());
3250 ss.str(t->property("tv-usec")->value());
3252 ut->set_timestamp(tv);
3254 for (XMLNodeConstIterator child_it = t->children().begin();
3255 child_it != t->children().end(); child_it++)
3257 XMLNode *n = *child_it;
3260 if (n->name() == "MementoCommand" ||
3261 n->name() == "MementoUndoCommand" ||
3262 n->name() == "MementoRedoCommand") {
3264 if ((c = memento_command_factory(n))) {
3268 } else if (n->name() == "NoteDiffCommand") {
3269 PBD::ID id (n->property("midi-source")->value());
3270 boost::shared_ptr<MidiSource> midi_source =
3271 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3273 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3275 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3278 } else if (n->name() == "SysExDiffCommand") {
3280 PBD::ID id (n->property("midi-source")->value());
3281 boost::shared_ptr<MidiSource> midi_source =
3282 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3284 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3286 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3289 } else if (n->name() == "PatchChangeDiffCommand") {
3291 PBD::ID id (n->property("midi-source")->value());
3292 boost::shared_ptr<MidiSource> midi_source =
3293 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3295 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3297 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3300 } else if (n->name() == "StatefulDiffCommand") {
3301 if ((c = stateful_diff_command_factory (n))) {
3302 ut->add_command (c);
3305 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3316 Session::config_changed (std::string p, bool ours)
3322 if (p == "seamless-loop") {
3324 } else if (p == "rf-speed") {
3326 } else if (p == "auto-loop") {
3328 } else if (p == "auto-input") {
3330 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3331 /* auto-input only makes a difference if we're rolling */
3332 set_track_monitor_input_status (!config.get_auto_input());
3335 } else if (p == "punch-in") {
3339 if ((location = _locations->auto_punch_location()) != 0) {
3341 if (config.get_punch_in ()) {
3342 replace_event (SessionEvent::PunchIn, location->start());
3344 remove_event (location->start(), SessionEvent::PunchIn);
3348 } else if (p == "punch-out") {
3352 if ((location = _locations->auto_punch_location()) != 0) {
3354 if (config.get_punch_out()) {
3355 replace_event (SessionEvent::PunchOut, location->end());
3357 clear_events (SessionEvent::PunchOut);
3361 } else if (p == "edit-mode") {
3363 Glib::Threads::Mutex::Lock lm (playlists->lock);
3365 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3366 (*i)->set_edit_mode (Config->get_edit_mode ());
3369 } else if (p == "use-video-sync") {
3371 waiting_for_sync_offset = config.get_use_video_sync();
3373 } else if (p == "mmc-control") {
3375 //poke_midi_thread ();
3377 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3379 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3381 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3383 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3385 } else if (p == "midi-control") {
3387 //poke_midi_thread ();
3389 } else if (p == "raid-path") {
3391 setup_raid_path (config.get_raid_path());
3393 } else if (p == "timecode-format") {
3397 } else if (p == "video-pullup") {
3401 } else if (p == "seamless-loop") {
3403 if (play_loop && transport_rolling()) {
3404 // to reset diskstreams etc
3405 request_play_loop (true);
3408 } else if (p == "rf-speed") {
3410 cumulative_rf_motion = 0;
3413 } else if (p == "click-sound") {
3415 setup_click_sounds (1);
3417 } else if (p == "click-emphasis-sound") {
3419 setup_click_sounds (-1);
3421 } else if (p == "clicking") {
3423 if (Config->get_clicking()) {
3424 if (_click_io && click_data) { // don't require emphasis data
3431 } else if (p == "click-gain") {
3434 _click_gain->set_gain (Config->get_click_gain(), this);
3437 } else if (p == "send-mtc") {
3439 if (Config->get_send_mtc ()) {
3440 /* mark us ready to send */
3441 next_quarter_frame_to_send = 0;
3444 } else if (p == "send-mmc") {
3446 _mmc->enable_send (Config->get_send_mmc ());
3448 } else if (p == "midi-feedback") {
3450 session_midi_feedback = Config->get_midi_feedback();
3452 } else if (p == "jack-time-master") {
3454 engine().reset_timebase ();
3456 } else if (p == "native-file-header-format") {
3458 if (!first_file_header_format_reset) {
3459 reset_native_file_format ();
3462 first_file_header_format_reset = false;
3464 } else if (p == "native-file-data-format") {
3466 if (!first_file_data_format_reset) {
3467 reset_native_file_format ();
3470 first_file_data_format_reset = false;
3472 } else if (p == "external-sync") {
3473 if (!config.get_external_sync()) {
3474 drop_sync_source ();
3476 switch_to_sync_source (Config->get_sync_source());
3478 } else if (p == "denormal-model") {
3480 } else if (p == "history-depth") {
3481 set_history_depth (Config->get_history_depth());
3482 } else if (p == "remote-model") {
3483 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3486 } else if (p == "initial-program-change") {
3488 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3491 buf[0] = MIDI::program; // channel zero by default
3492 buf[1] = (Config->get_initial_program_change() & 0x7f);
3494 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3496 } else if (p == "solo-mute-override") {
3497 // catch_up_on_solo_mute_override ();
3498 } else if (p == "listen-position" || p == "pfl-position") {
3499 listen_position_changed ();
3500 } else if (p == "solo-control-is-listen-control") {
3501 solo_control_mode_changed ();
3502 } else if (p == "solo-mute-gain") {
3503 _solo_cut_control->Changed();
3504 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3505 last_timecode_valid = false;
3506 } else if (p == "playback-buffer-seconds") {
3507 AudioSource::allocate_working_buffers (frame_rate());
3508 } else if (p == "ltc-source-port") {
3509 reconnect_ltc_input ();
3510 } else if (p == "ltc-sink-port") {
3511 reconnect_ltc_output ();
3512 } else if (p == "timecode-generator-offset") {
3513 ltc_tx_parse_offset();
3520 Session::set_history_depth (uint32_t d)
3522 _history.set_depth (d);
3526 Session::load_diskstreams_2X (XMLNode const & node, int)
3529 XMLNodeConstIterator citer;
3531 clist = node.children();
3533 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3536 /* diskstreams added automatically by DiskstreamCreated handler */
3537 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3538 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3539 _diskstreams_2X.push_back (dsp);
3541 error << _("Session: unknown diskstream type in XML") << endmsg;
3545 catch (failed_constructor& err) {
3546 error << _("Session: could not load diskstream via XML state") << endmsg;
3554 /** Connect things to the MMC object */
3556 Session::setup_midi_machine_control ()
3558 _mmc = new MIDI::MachineControl;
3559 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3561 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3562 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3563 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3564 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3565 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3566 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3567 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3568 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3569 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3570 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3571 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3572 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3573 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3575 /* also handle MIDI SPP because its so common */
3577 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3578 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3579 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3582 boost::shared_ptr<Controllable>
3583 Session::solo_cut_control() const
3585 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3586 controls in Ardour that currently get presented to the user in the GUI that require
3587 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3589 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3590 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3594 return _solo_cut_control;
3598 Session::rename (const std::string& new_name, bool after_copy)
3600 string legal_name = legalize_for_path (new_name);
3606 string const old_sources_root = _session_dir->sources_root();
3611 * interchange subdirectory
3615 * Backup files are left unchanged and not renamed.
3618 /* pass one: not 100% safe check that the new directory names don't
3623 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3626 /* primary session directory */
3632 /* this is a stupid hack because Glib::path_get_dirname() is
3633 * lexical-only, and so passing it /a/b/c/ gives a different
3634 * result than passing it /a/b/c ...
3637 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3638 oldstr = oldstr.substr (0, oldstr.length() - 1);
3641 string base = Glib::path_get_dirname (oldstr);
3642 string p = Glib::path_get_basename (oldstr);
3644 newstr = Glib::build_filename (base, legal_name);
3647 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3657 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3662 /* this is a stupid hack because Glib::path_get_dirname() is
3663 * lexical-only, and so passing it /a/b/c/ gives a different
3664 * result than passing it /a/b/c ...
3667 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3668 oldstr = oldstr.substr (0, oldstr.length() - 1);
3674 string base = Glib::path_get_dirname (oldstr);
3675 newstr = Glib::build_filename (base, legal_name);
3679 cerr << "Rename " << oldstr << " => " << newstr << endl;
3680 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3681 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3686 /* Reset path in "session dirs" */
3690 /* reset primary SessionDirectory object */
3693 (*_session_dir) = newstr;
3698 /* now rename directory below session_dir/interchange */
3700 string old_interchange_dir;
3701 string new_interchange_dir;
3703 /* use newstr here because we renamed the path that used to be oldstr to newstr above */
3705 v.push_back (newstr);
3706 v.push_back (interchange_dir_name);
3707 v.push_back (Glib::path_get_basename (oldstr));
3709 old_interchange_dir = Glib::build_filename (v);
3712 v.push_back (newstr);
3713 v.push_back (interchange_dir_name);
3714 v.push_back (legal_name);
3716 new_interchange_dir = Glib::build_filename (v);
3718 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3720 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3721 error << string_compose (_("renaming %s as %2 failed (%3)"),
3722 old_interchange_dir, new_interchange_dir,
3731 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + statefile_suffix;
3732 newstr= Glib::build_filename (new_path, legal_name) + statefile_suffix;
3734 cerr << "Rename " << oldstr << " => " << newstr << endl;
3736 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3737 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3743 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3745 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3746 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3748 cerr << "Rename " << oldstr << " => " << newstr << endl;
3750 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3751 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3757 /* remove old name from recent sessions */
3758 remove_recent_sessions (_path);
3762 _current_snapshot_name = new_name;
3767 /* save state again to get everything just right */
3769 save_state (_current_snapshot_name);
3771 /* add to recent sessions */
3773 store_recent_sessions (new_name, _path);
3779 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3781 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3785 if (!tree.read (xmlpath)) {
3793 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3796 bool found_sr = false;
3797 bool found_data_format = false;
3799 if (get_session_info_from_path (tree, xmlpath)) {
3805 const XMLProperty* prop;
3806 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3807 sample_rate = atoi (prop->value());
3811 const XMLNodeList& children (tree.root()->children());
3812 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3813 const XMLNode* child = *c;
3814 if (child->name() == "Config") {
3815 const XMLNodeList& options (child->children());
3816 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3817 const XMLNode* option = *oc;
3818 const XMLProperty* name = option->property("name");
3824 if (name->value() == "native-file-data-format") {
3825 const XMLProperty* value = option->property ("value");
3827 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3829 found_data_format = true;
3835 if (found_data_format) {
3840 return !(found_sr && found_data_format); // zero if they are both found
3843 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
3844 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
3847 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
3851 SourcePathMap source_path_map;
3853 boost::shared_ptr<AudioFileSource> afs;
3858 Glib::Threads::Mutex::Lock lm (source_lock);
3860 cerr << " total sources = " << sources.size();
3862 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3863 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3869 if (fs->within_session()) {
3870 cerr << "skip " << fs->name() << endl;
3874 if (source_path_map.find (fs->path()) != source_path_map.end()) {
3875 source_path_map[fs->path()].push_back (fs);
3877 SeveralFileSources v;
3879 source_path_map.insert (make_pair (fs->path(), v));
3885 cerr << " fsources = " << total << endl;
3887 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
3889 /* tell caller where we are */
3891 string old_path = i->first;
3893 callback (n, total, old_path);
3895 cerr << old_path << endl;
3899 switch (i->second.front()->type()) {
3900 case DataType::AUDIO:
3901 new_path = new_audio_source_path_for_embedded (old_path);
3904 case DataType::MIDI:
3908 cerr << "Move " << old_path << " => " << new_path << endl;
3910 if (!copy_file (old_path, new_path)) {
3911 cerr << "failed !\n";
3915 /* make sure we stop looking in the external
3916 dir/folder. Remember, this is an all-or-nothing
3917 operations, it doesn't merge just some files.
3919 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
3921 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
3922 (*f)->set_path (new_path);
3927 save_state ("", false, false);
3933 bool accept_all_files (string const &, void *)
3939 Session::save_as (SaveAs& saveas)
3941 vector<string> files;
3942 string current_folder = Glib::path_get_dirname (_path);
3943 string new_folder = legalize_for_path (saveas.new_name);
3944 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
3945 int64_t total_bytes = 0;
3950 /* get total size */
3952 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
3954 /* need to clear this because
3955 * find_files_matching_filter() is cumulative
3960 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
3962 all += files.size();
3964 cerr << (*sd).path << " Contained " << files.size() << " total now " << all << endl;
3966 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
3969 if ((*i).find (X_("interchange")) == string::npos || saveas.copy_media) {
3970 g_stat ((*i).c_str(), &gsb);
3971 total_bytes += gsb.st_size;
3974 cerr << "\ttotal size now " << total_bytes << endl;
3977 /* Create the new session directory */
3979 string old_path = _path;
3980 string old_name = _name;
3981 string old_snapshot = _current_snapshot_name;
3982 string old_sd = _session_dir->root_path();
3984 (*_session_dir) = to_dir;
3986 if (!_session_dir->create()) {
3990 cerr << "Created new session dir " << _session_dir->root_path() << endl;
3993 if (saveas.copy_media) {
3995 /* copy all media files. Find each location in
3996 * session_dirs, and copy files from there to
4000 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4002 /* need to clear this because
4003 * find_files_matching_filter() is cumulative
4008 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4010 const size_t prefix_len = (*sd).path.size();
4012 /* copy all media files (everything below
4016 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4017 std::string from = *i;
4020 if ((*i).find (X_("interchange")) != string::npos) {
4025 g_stat ((*i).c_str(), &gsb);
4027 /* strip the session dir prefix from
4028 * each full path, then prepend new
4029 * to_dir to give complete path.
4032 std::string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
4034 cerr << "Copy " << from << " to " << to << endl;
4036 if (!copy_file (from, to)) {
4037 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4040 copied += gsb.st_size;
4041 double fraction = (double) copied / total_bytes;
4043 /* tell someone "X percent, file M of
4044 * N"; M is one-based
4049 cerr << "PROGRESS " << fraction << "%, " << cnt << " of " << all << endl;
4052 if (!saveas.Progress (fraction, cnt, all)) {
4053 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4062 _current_snapshot_name = saveas.new_name;
4063 _name = saveas.new_name;
4065 cerr << "New path = " << _path << endl;
4067 if (!saveas.copy_media && saveas.switch_to) {
4069 /* need to make all internal file sources point to old session */
4071 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4072 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4074 if (fs && fs->within_session()) {
4076 cerr << "fs " << fs->name() << " is inside session " << fs->path() << endl;
4078 /* give it an absolute path referencing
4079 * the original session. Should be
4080 * easy, but in general, we don't
4081 * actually know where it lives - it
4082 * could be in any session dir. So we
4083 * have to look for it.
4085 * Note that the session_dirs list
4088 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4089 SessionDirectory sdir ((*sd).path);
4091 switch (fs->type()) {
4092 case DataType::AUDIO:
4093 file_dir = sdir.sound_path();
4095 case DataType::MIDI:
4096 file_dir = sdir.midi_path();
4101 string possible_path = Glib::build_filename (file_dir, fs->path());
4102 if (Glib::file_test (possible_path, Glib::FILE_TEST_EXISTS)) {
4104 cerr << "Reset path for " << fs->name() << " @ " << fs->path() << " to " << possible_path << endl;
4105 fs->set_path (possible_path);
4114 bool was_dirty = dirty ();
4116 cerr << "Saving state\n";
4118 save_state ("", false, false);
4119 save_default_options ();
4121 if (saveas.copy_media && saveas.copy_external) {
4122 if (consolidate_all_media()) {
4123 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4127 if (!saveas.switch_to) {
4129 /* switch back to the way things were */
4133 _current_snapshot_name = old_snapshot;
4135 (*_session_dir) = old_sd;
4143 /* prune session dirs
4148 session_dirs.clear ();
4149 session_dirs.push_back (sp);
4150 refresh_disk_space ();
4152 cerr << "pruned session dirs, sd = " << _session_dir->root_path()
4153 << " path = " << _path << endl;
4158 cerr << "copying/saveas failed\n";
4160 /* recursively remove all the directories */
4162 remove_directory (to_dir);
4168 cerr << "saveas completed successfully\n";
4174 /** Check all sources used by the current snapshot
4175 * and make a copy of any external media within
4179 Session::consolidate_all_media ()