2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
31 #include <cstdio> /* snprintf(3) ... grrr */
44 #include <sys/param.h>
45 #include <sys/mount.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
53 #include <glib/gstdio.h>
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/boost_debug.h"
67 #include "pbd/basename.h"
68 #include "pbd/controllable_descriptor.h"
69 #include "pbd/enumwriter.h"
70 #include "pbd/error.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/convert.h"
76 #include "pbd/localtime_r.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/playlist_source.h"
101 #include "ardour/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/proxy_controllable.h"
104 #include "ardour/recent_sessions.h"
105 #include "ardour/region_factory.h"
106 #include "ardour/route_group.h"
107 #include "ardour/send.h"
108 #include "ardour/session.h"
109 #include "ardour/session_directory.h"
110 #include "ardour/session_metadata.h"
111 #include "ardour/session_playlists.h"
112 #include "ardour/session_state_utils.h"
113 #include "ardour/silentfilesource.h"
114 #include "ardour/sndfilesource.h"
115 #include "ardour/source_factory.h"
116 #include "ardour/speakers.h"
117 #include "ardour/template_utils.h"
118 #include "ardour/tempo.h"
119 #include "ardour/ticker.h"
120 #include "ardour/user_bundle.h"
122 #include "control_protocol/control_protocol.h"
128 using namespace ARDOUR;
132 Session::pre_engine_init (string fullpath)
134 if (fullpath.empty()) {
136 throw failed_constructor();
139 /* discover canonical fullpath */
141 _path = canonical_path(fullpath);
145 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
147 /* finish initialization that can't be done in a normal C++ constructor
151 timerclear (&last_mmc_step);
152 g_atomic_int_set (&processing_prohibited, 0);
153 g_atomic_int_set (&_record_status, Disabled);
154 g_atomic_int_set (&_playback_load, 100);
155 g_atomic_int_set (&_capture_load, 100);
157 _all_route_group->set_active (true, this);
158 interpolation.add_channel_to (0, 0);
160 if (config.get_use_video_sync()) {
161 waiting_for_sync_offset = true;
163 waiting_for_sync_offset = false;
166 last_rr_session_dir = session_dirs.begin();
168 set_history_depth (Config->get_history_depth());
170 /* default: assume simple stereo speaker configuration */
172 _speakers->setup_default_speakers (2);
174 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
175 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
176 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
177 add_controllable (_solo_cut_control);
179 /* These are all static "per-class" signals */
181 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
182 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
183 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
184 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
185 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
187 /* stop IO objects from doing stuff until we're ready for them */
189 Delivery::disable_panners ();
190 IO::disable_connecting ();
192 AudioFileSource::set_peak_dir (_session_dir->peak_path());
196 Session::post_engine_init ()
198 BootMessage (_("Set block size and sample rate"));
200 set_block_size (_engine.samples_per_cycle());
201 set_frame_rate (_engine.sample_rate());
203 BootMessage (_("Using configuration"));
205 _midi_ports = new MidiPortManager;
207 MIDISceneChanger* msc;
209 _scene_changer = msc = new MIDISceneChanger (*this);
210 msc->set_input_port (scene_input_port());
211 msc->set_output_port (scene_out());
213 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
214 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
216 setup_midi_machine_control ();
218 if (_butler->start_thread()) {
222 if (start_midi_thread ()) {
226 setup_click_sounds (0);
227 setup_midi_control ();
229 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
230 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
233 /* tempo map requires sample rate knowledge */
236 _tempo_map = new TempoMap (_current_frame_rate);
237 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
239 /* MidiClock requires a tempo map */
241 midi_clock = new MidiClockTicker ();
242 midi_clock->set_session (this);
244 /* crossfades require sample rate knowledge */
246 SndFileSource::setup_standard_crossfades (*this, frame_rate());
247 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
249 AudioDiskstream::allocate_working_buffers();
250 refresh_disk_space ();
252 /* we're finally ready to call set_state() ... all objects have
253 * been created, the engine is running.
257 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
261 // set_state() will call setup_raid_path(), but if it's a new session we need
262 // to call setup_raid_path() here.
263 setup_raid_path (_path);
268 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
269 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
271 Config->map_parameters (ff);
272 config.map_parameters (ft);
274 /* Reset all panners */
276 Delivery::reset_panners ();
278 /* this will cause the CPM to instantiate any protocols that are in use
279 * (or mandatory), which will pass it this Session, and then call
280 * set_state() on each instantiated protocol to match stored state.
283 ControlProtocolManager::instance().set_session (this);
285 /* This must be done after the ControlProtocolManager set_session above,
286 as it will set states for ports which the ControlProtocolManager creates.
289 // XXX set state of MIDI::Port's
290 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
292 /* And this must be done after the MIDI::Manager::set_port_states as
293 * it will try to make connections whose details are loaded by set_port_states.
298 /* Let control protocols know that we are now all connected, so they
299 * could start talking to surfaces if they want to.
302 ControlProtocolManager::instance().midi_connectivity_established ();
304 if (_is_new && !no_auto_connect()) {
305 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
306 auto_connect_master_bus ();
309 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
311 /* update latencies */
313 initialize_latencies ();
315 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
316 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
317 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
319 } catch (AudioEngine::PortRegistrationFailure& err) {
320 /* handle this one in a different way than all others, so that its clear what happened */
321 error << err.what() << endmsg;
327 BootMessage (_("Reset Remote Controls"));
329 // send_full_time_code (0);
330 _engine.transport_locate (0);
332 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
333 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
335 MIDI::Name::MidiPatchManager::instance().set_session (this);
338 /* initial program change will be delivered later; see ::config_changed() */
340 _state_of_the_state = Clean;
342 Port::set_connecting_blocked (false);
344 DirtyChanged (); /* EMIT SIGNAL */
348 } else if (state_was_pending) {
350 remove_pending_capture_state ();
351 state_was_pending = false;
358 Session::raid_path () const
360 Searchpath raid_search_path;
362 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
363 raid_search_path += (*i).path;
366 return raid_search_path.to_string ();
370 Session::setup_raid_path (string path)
379 session_dirs.clear ();
381 Searchpath search_path(path);
382 Searchpath sound_search_path;
383 Searchpath midi_search_path;
385 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
387 sp.blocks = 0; // not needed
388 session_dirs.push_back (sp);
390 SessionDirectory sdir(sp.path);
392 sound_search_path += sdir.sound_path ();
393 midi_search_path += sdir.midi_path ();
396 // reset the round-robin soundfile path thingie
397 last_rr_session_dir = session_dirs.begin();
401 Session::path_is_within_session (const std::string& path)
403 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
404 if (PBD::path_is_within (i->path, path)) {
412 Session::ensure_subdirs ()
416 dir = session_directory().peak_path();
418 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
419 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
423 dir = session_directory().sound_path();
425 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
426 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
430 dir = session_directory().midi_path();
432 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
433 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
437 dir = session_directory().dead_path();
439 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
440 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
444 dir = session_directory().export_path();
446 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
447 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
451 dir = analysis_dir ();
453 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
454 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
458 dir = plugins_dir ();
460 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
461 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
465 dir = externals_dir ();
467 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
468 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
475 /** @param session_template directory containing session template, or empty.
476 * Caller must not hold process lock.
479 Session::create (const string& session_template, BusProfile* bus_profile)
481 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
482 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
486 if (ensure_subdirs ()) {
490 _writable = exists_and_writable (_path);
492 if (!session_template.empty()) {
493 std::string in_path = session_template_dir_to_file (session_template);
495 ifstream in(in_path.c_str());
498 /* no need to call legalize_for_path() since the string
499 * in session_template is already a legal path name
501 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
503 ofstream out(out_path.c_str());
509 /* Copy plugin state files from template to new session */
510 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
511 copy_recurse (template_plugins, plugins_dir ());
516 error << string_compose (_("Could not open %1 for writing session template"), out_path)
522 error << string_compose (_("Could not open session template %1 for reading"), in_path)
529 /* set initial start + end point */
531 _state_of_the_state = Clean;
533 /* set up Master Out and Control Out if necessary */
538 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
540 if (bus_profile->master_out_channels) {
541 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
545 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
546 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
549 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
550 r->input()->ensure_io (count, false, this);
551 r->output()->ensure_io (count, false, this);
557 /* prohibit auto-connect to master, because there isn't one */
558 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
562 add_routes (rl, false, false, false);
565 /* this allows the user to override settings with an environment variable.
568 if (no_auto_connect()) {
569 bus_profile->input_ac = AutoConnectOption (0);
570 bus_profile->output_ac = AutoConnectOption (0);
573 Config->set_input_auto_connect (bus_profile->input_ac);
574 Config->set_output_auto_connect (bus_profile->output_ac);
577 if (Config->get_use_monitor_bus() && bus_profile) {
578 add_monitor_section ();
585 Session::maybe_write_autosave()
587 if (dirty() && record_status() != Recording) {
588 save_state("", true);
593 Session::remove_pending_capture_state ()
595 std::string pending_state_file_path(_session_dir->root_path());
597 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
599 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
601 if (g_remove (pending_state_file_path.c_str()) != 0) {
602 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
603 pending_state_file_path, g_strerror (errno)) << endmsg;
607 /** Rename a state file.
608 * @param old_name Old snapshot name.
609 * @param new_name New snapshot name.
612 Session::rename_state (string old_name, string new_name)
614 if (old_name == _current_snapshot_name || old_name == _name) {
615 /* refuse to rename the current snapshot or the "main" one */
619 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
620 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
622 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
623 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
625 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
626 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
627 old_name, new_name, g_strerror(errno)) << endmsg;
631 /** Remove a state file.
632 * @param snapshot_name Snapshot name.
635 Session::remove_state (string snapshot_name)
637 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
638 // refuse to remove the current snapshot or the "main" one
642 std::string xml_path(_session_dir->root_path());
644 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
646 if (!create_backup_file (xml_path)) {
647 // don't remove it if a backup can't be made
648 // create_backup_file will log the error.
653 if (g_remove (xml_path.c_str()) != 0) {
654 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
655 xml_path, g_strerror (errno)) << endmsg;
659 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
661 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
664 std::string xml_path(_session_dir->root_path());
666 /* prevent concurrent saves from different threads */
668 Glib::Threads::Mutex::Lock lm (save_state_lock);
670 if (!_writable || (_state_of_the_state & CannotSave)) {
674 if (g_atomic_int_get(&_suspend_save)) {
678 _save_queued = false;
680 if (!_engine.connected ()) {
681 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
687 /* tell sources we're saving first, in case they write out to a new file
688 * which should be saved with the state rather than the old one */
689 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
691 i->second->session_saved();
692 } catch (Evoral::SMF::FileError& e) {
693 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
697 SessionSaveUnderway (); /* EMIT SIGNAL */
700 tree.set_root (&get_template());
702 tree.set_root (&get_state());
705 if (snapshot_name.empty()) {
706 snapshot_name = _current_snapshot_name;
707 } else if (switch_to_snapshot) {
708 _current_snapshot_name = snapshot_name;
713 /* proper save: use statefile_suffix (.ardour in English) */
715 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
717 /* make a backup copy of the old file */
719 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
720 // create_backup_file will log the error
726 /* pending save: use pending_suffix (.pending in English) */
727 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
730 std::string tmp_path(_session_dir->root_path());
731 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
733 cerr << "actually writing state to " << tmp_path << endl;
735 if (!tree.write (tmp_path)) {
736 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
737 if (g_remove (tmp_path.c_str()) != 0) {
738 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
739 tmp_path, g_strerror (errno)) << endmsg;
745 cerr << "renaming state to " << xml_path << endl;
747 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
748 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
749 tmp_path, xml_path, g_strerror(errno)) << endmsg;
750 if (g_remove (tmp_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
752 tmp_path, g_strerror (errno)) << endmsg;
760 save_history (snapshot_name);
762 bool was_dirty = dirty();
764 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
767 DirtyChanged (); /* EMIT SIGNAL */
770 StateSaved (snapshot_name); /* EMIT SIGNAL */
777 Session::restore_state (string snapshot_name)
779 if (load_state (snapshot_name) == 0) {
780 set_state (*state_tree->root(), Stateful::loading_state_version);
787 Session::load_state (string snapshot_name)
792 state_was_pending = false;
794 /* check for leftover pending state from a crashed capture attempt */
796 std::string xmlpath(_session_dir->root_path());
797 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
799 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
801 /* there is pending state from a crashed capture attempt */
803 boost::optional<int> r = AskAboutPendingState();
804 if (r.get_value_or (1)) {
805 state_was_pending = true;
809 if (!state_was_pending) {
810 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
813 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
814 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
815 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
816 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
821 state_tree = new XMLTree;
825 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
827 if (!state_tree->read (xmlpath)) {
828 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
834 XMLNode& root (*state_tree->root());
836 if (root.name() != X_("Session")) {
837 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
843 const XMLProperty* prop;
845 if ((prop = root.property ("version")) == 0) {
846 /* no version implies very old version of Ardour */
847 Stateful::loading_state_version = 1000;
849 if (prop->value().find ('.') != string::npos) {
850 /* old school version format */
851 if (prop->value()[0] == '2') {
852 Stateful::loading_state_version = 2000;
854 Stateful::loading_state_version = 3000;
857 Stateful::loading_state_version = atoi (prop->value());
861 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
863 std::string backup_path(_session_dir->root_path());
864 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
865 backup_path = Glib::build_filename (backup_path, backup_filename);
867 // only create a backup for a given statefile version once
869 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
871 VersionMismatch (xmlpath, backup_path);
873 if (!copy_file (xmlpath, backup_path)) {;
883 Session::load_options (const XMLNode& node)
885 LocaleGuard lg (X_("C"));
886 config.set_variables (node);
891 Session::save_default_options ()
893 return config.save_state();
903 Session::get_template()
905 /* if we don't disable rec-enable, diskstreams
906 will believe they need to store their capture
907 sources in their state node.
910 disable_record (false);
916 Session::state (bool full_state)
918 XMLNode* node = new XMLNode("Session");
922 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
923 node->add_property("version", buf);
925 /* store configuration settings */
929 node->add_property ("name", _name);
930 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
931 node->add_property ("sample-rate", buf);
933 if (session_dirs.size() > 1) {
937 vector<space_and_path>::iterator i = session_dirs.begin();
938 vector<space_and_path>::iterator next;
940 ++i; /* skip the first one */
944 while (i != session_dirs.end()) {
948 if (next != session_dirs.end()) {
949 p += G_SEARCHPATH_SEPARATOR;
958 child = node->add_child ("Path");
959 child->add_content (p);
963 /* save the ID counter */
965 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
966 node->add_property ("id-counter", buf);
968 /* save the event ID counter */
970 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
971 node->add_property ("event-counter", buf);
973 /* various options */
975 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
976 if (!midi_port_nodes.empty()) {
977 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
978 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
979 midi_port_stuff->add_child_nocopy (**n);
981 node->add_child_nocopy (*midi_port_stuff);
984 node->add_child_nocopy (config.get_variables ());
986 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
988 child = node->add_child ("Sources");
991 Glib::Threads::Mutex::Lock sl (source_lock);
993 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
995 /* Don't save information about non-file Sources, or
996 * about non-destructive file sources that are empty
997 * and unused by any regions.
1000 boost::shared_ptr<FileSource> fs;
1002 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1004 if (!fs->destructive()) {
1005 if (fs->empty() && !fs->used()) {
1010 child->add_child_nocopy (siter->second->get_state());
1015 child = node->add_child ("Regions");
1018 Glib::Threads::Mutex::Lock rl (region_lock);
1019 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1020 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1021 boost::shared_ptr<Region> r = i->second;
1022 /* only store regions not attached to playlists */
1023 if (r->playlist() == 0) {
1024 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1025 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1027 child->add_child_nocopy (r->get_state ());
1032 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1034 if (!cassocs.empty()) {
1035 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1037 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1039 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1040 i->first->id().print (buf, sizeof (buf));
1041 can->add_property (X_("copy"), buf);
1042 i->second->id().print (buf, sizeof (buf));
1043 can->add_property (X_("original"), buf);
1044 ca->add_child_nocopy (*can);
1050 node->add_child_nocopy (_locations->get_state());
1052 // for a template, just create a new Locations, populate it
1053 // with the default start and end, and get the state for that.
1054 Locations loc (*this);
1055 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1056 range->set (max_framepos, 0);
1058 node->add_child_nocopy (loc.get_state());
1061 child = node->add_child ("Bundles");
1063 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1064 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1065 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1067 child->add_child_nocopy (b->get_state());
1072 child = node->add_child ("Routes");
1074 boost::shared_ptr<RouteList> r = routes.reader ();
1076 RoutePublicOrderSorter cmp;
1077 RouteList public_order (*r);
1078 public_order.sort (cmp);
1080 /* the sort should have put control outs first */
1083 assert (_monitor_out == public_order.front());
1086 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1087 if (!(*i)->is_auditioner()) {
1089 child->add_child_nocopy ((*i)->get_state());
1091 child->add_child_nocopy ((*i)->get_template());
1097 playlists->add_state (node, full_state);
1099 child = node->add_child ("RouteGroups");
1100 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1101 child->add_child_nocopy ((*i)->get_state());
1105 XMLNode* gain_child = node->add_child ("Click");
1106 gain_child->add_child_nocopy (_click_io->state (full_state));
1107 gain_child->add_child_nocopy (_click_gain->state (full_state));
1111 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1112 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1116 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1117 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1120 node->add_child_nocopy (_speakers->get_state());
1121 node->add_child_nocopy (_tempo_map->get_state());
1122 node->add_child_nocopy (get_control_protocol_state());
1125 node->add_child_copy (*_extra_xml);
1132 Session::get_control_protocol_state ()
1134 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1135 return cpm.get_state();
1139 Session::set_state (const XMLNode& node, int version)
1143 const XMLProperty* prop;
1146 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1148 if (node.name() != X_("Session")) {
1149 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1153 if ((prop = node.property ("name")) != 0) {
1154 _name = prop->value ();
1157 if ((prop = node.property (X_("sample-rate"))) != 0) {
1159 _nominal_frame_rate = atoi (prop->value());
1161 if (_nominal_frame_rate != _current_frame_rate) {
1162 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1163 if (r.get_value_or (0)) {
1169 setup_raid_path(_session_dir->root_path());
1171 if ((prop = node.property (X_("id-counter"))) != 0) {
1173 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1174 ID::init_counter (x);
1176 /* old sessions used a timebased counter, so fake
1177 the startup ID counter based on a standard
1182 ID::init_counter (now);
1185 if ((prop = node.property (X_("event-counter"))) != 0) {
1186 Evoral::init_event_id_counter (atoi (prop->value()));
1190 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1191 _midi_ports->set_midi_port_states (child->children());
1194 IO::disable_connecting ();
1196 Stateful::save_extra_xml (node);
1198 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1199 load_options (*child);
1200 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1201 load_options (*child);
1203 error << _("Session: XML state has no options section") << endmsg;
1206 if (version >= 3000) {
1207 if ((child = find_named_node (node, "Metadata")) == 0) {
1208 warning << _("Session: XML state has no metadata section") << endmsg;
1209 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1214 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1215 _speakers->set_state (*child, version);
1218 if ((child = find_named_node (node, "Sources")) == 0) {
1219 error << _("Session: XML state has no sources section") << endmsg;
1221 } else if (load_sources (*child)) {
1225 if ((child = find_named_node (node, "TempoMap")) == 0) {
1226 error << _("Session: XML state has no Tempo Map section") << endmsg;
1228 } else if (_tempo_map->set_state (*child, version)) {
1232 if ((child = find_named_node (node, "Locations")) == 0) {
1233 error << _("Session: XML state has no locations section") << endmsg;
1235 } else if (_locations->set_state (*child, version)) {
1239 locations_changed ();
1241 if (_session_range_location) {
1242 AudioFileSource::set_header_position_offset (_session_range_location->start());
1245 if ((child = find_named_node (node, "Regions")) == 0) {
1246 error << _("Session: XML state has no Regions section") << endmsg;
1248 } else if (load_regions (*child)) {
1252 if ((child = find_named_node (node, "Playlists")) == 0) {
1253 error << _("Session: XML state has no playlists section") << endmsg;
1255 } else if (playlists->load (*this, *child)) {
1259 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1261 } else if (playlists->load_unused (*this, *child)) {
1265 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1266 if (load_compounds (*child)) {
1271 if (version >= 3000) {
1272 if ((child = find_named_node (node, "Bundles")) == 0) {
1273 warning << _("Session: XML state has no bundles section") << endmsg;
1276 /* We can't load Bundles yet as they need to be able
1277 to convert from port names to Port objects, which can't happen until
1279 _bundle_xml_node = new XMLNode (*child);
1283 if (version < 3000) {
1284 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1285 error << _("Session: XML state has no diskstreams section") << endmsg;
1287 } else if (load_diskstreams_2X (*child, version)) {
1292 if ((child = find_named_node (node, "Routes")) == 0) {
1293 error << _("Session: XML state has no routes section") << endmsg;
1295 } else if (load_routes (*child, version)) {
1299 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1300 _diskstreams_2X.clear ();
1302 if (version >= 3000) {
1304 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1305 error << _("Session: XML state has no route groups section") << endmsg;
1307 } else if (load_route_groups (*child, version)) {
1311 } else if (version < 3000) {
1313 if ((child = find_named_node (node, "EditGroups")) == 0) {
1314 error << _("Session: XML state has no edit groups section") << endmsg;
1316 } else if (load_route_groups (*child, version)) {
1320 if ((child = find_named_node (node, "MixGroups")) == 0) {
1321 error << _("Session: XML state has no mix groups section") << endmsg;
1323 } else if (load_route_groups (*child, version)) {
1328 if ((child = find_named_node (node, "Click")) == 0) {
1329 warning << _("Session: XML state has no click section") << endmsg;
1330 } else if (_click_io) {
1331 setup_click_state (&node);
1334 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1335 ControlProtocolManager::instance().set_state (*child, version);
1338 update_have_rec_enabled_track ();
1340 /* here beginneth the second phase ... */
1342 StateReady (); /* EMIT SIGNAL */
1355 Session::load_routes (const XMLNode& node, int version)
1358 XMLNodeConstIterator niter;
1359 RouteList new_routes;
1361 nlist = node.children();
1365 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1367 boost::shared_ptr<Route> route;
1368 if (version < 3000) {
1369 route = XMLRouteFactory_2X (**niter, version);
1371 route = XMLRouteFactory (**niter, version);
1375 error << _("Session: cannot create Route from XML description.") << endmsg;
1379 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1381 new_routes.push_back (route);
1384 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1386 add_routes (new_routes, false, false, false);
1388 BootMessage (_("Finished adding tracks/busses"));
1393 boost::shared_ptr<Route>
1394 Session::XMLRouteFactory (const XMLNode& node, int version)
1396 boost::shared_ptr<Route> ret;
1398 if (node.name() != "Route") {
1402 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1404 DataType type = DataType::AUDIO;
1405 const XMLProperty* prop = node.property("default-type");
1408 type = DataType (prop->value());
1411 assert (type != DataType::NIL);
1415 boost::shared_ptr<Track> track;
1417 if (type == DataType::AUDIO) {
1418 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1420 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1423 if (track->init()) {
1427 if (track->set_state (node, version)) {
1431 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1432 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1437 enum Route::Flag flags = Route::Flag(0);
1438 const XMLProperty* prop = node.property("flags");
1440 flags = Route::Flag (string_2_enum (prop->value(), flags));
1443 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1445 if (r->init () == 0 && r->set_state (node, version) == 0) {
1446 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1447 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1456 boost::shared_ptr<Route>
1457 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1459 boost::shared_ptr<Route> ret;
1461 if (node.name() != "Route") {
1465 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1467 ds_prop = node.property (X_("diskstream"));
1470 DataType type = DataType::AUDIO;
1471 const XMLProperty* prop = node.property("default-type");
1474 type = DataType (prop->value());
1477 assert (type != DataType::NIL);
1481 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1482 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1486 if (i == _diskstreams_2X.end()) {
1487 error << _("Could not find diskstream for route") << endmsg;
1488 return boost::shared_ptr<Route> ();
1491 boost::shared_ptr<Track> track;
1493 if (type == DataType::AUDIO) {
1494 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1496 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1499 if (track->init()) {
1503 if (track->set_state (node, version)) {
1507 track->set_diskstream (*i);
1509 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1510 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1515 enum Route::Flag flags = Route::Flag(0);
1516 const XMLProperty* prop = node.property("flags");
1518 flags = Route::Flag (string_2_enum (prop->value(), flags));
1521 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1523 if (r->init () == 0 && r->set_state (node, version) == 0) {
1524 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1525 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1535 Session::load_regions (const XMLNode& node)
1538 XMLNodeConstIterator niter;
1539 boost::shared_ptr<Region> region;
1541 nlist = node.children();
1545 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1546 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1547 error << _("Session: cannot create Region from XML description.");
1548 const XMLProperty *name = (**niter).property("name");
1551 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1562 Session::load_compounds (const XMLNode& node)
1564 XMLNodeList calist = node.children();
1565 XMLNodeConstIterator caiter;
1566 XMLProperty *caprop;
1568 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1569 XMLNode* ca = *caiter;
1573 if ((caprop = ca->property (X_("original"))) == 0) {
1576 orig_id = caprop->value();
1578 if ((caprop = ca->property (X_("copy"))) == 0) {
1581 copy_id = caprop->value();
1583 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1584 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1586 if (!orig || !copy) {
1587 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1593 RegionFactory::add_compound_association (orig, copy);
1600 Session::load_nested_sources (const XMLNode& node)
1603 XMLNodeConstIterator niter;
1605 nlist = node.children();
1607 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1608 if ((*niter)->name() == "Source") {
1610 /* it may already exist, so don't recreate it unnecessarily
1613 XMLProperty* prop = (*niter)->property (X_("id"));
1615 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1619 ID source_id (prop->value());
1621 if (!source_by_id (source_id)) {
1624 SourceFactory::create (*this, **niter, true);
1626 catch (failed_constructor& err) {
1627 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1634 boost::shared_ptr<Region>
1635 Session::XMLRegionFactory (const XMLNode& node, bool full)
1637 const XMLProperty* type = node.property("type");
1641 const XMLNodeList& nlist = node.children();
1643 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1644 XMLNode *child = (*niter);
1645 if (child->name() == "NestedSource") {
1646 load_nested_sources (*child);
1650 if (!type || type->value() == "audio") {
1651 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1652 } else if (type->value() == "midi") {
1653 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1656 } catch (failed_constructor& err) {
1657 return boost::shared_ptr<Region> ();
1660 return boost::shared_ptr<Region> ();
1663 boost::shared_ptr<AudioRegion>
1664 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1666 const XMLProperty* prop;
1667 boost::shared_ptr<Source> source;
1668 boost::shared_ptr<AudioSource> as;
1670 SourceList master_sources;
1671 uint32_t nchans = 1;
1674 if (node.name() != X_("Region")) {
1675 return boost::shared_ptr<AudioRegion>();
1678 if ((prop = node.property (X_("channels"))) != 0) {
1679 nchans = atoi (prop->value().c_str());
1682 if ((prop = node.property ("name")) == 0) {
1683 cerr << "no name for this region\n";
1687 if ((prop = node.property (X_("source-0"))) == 0) {
1688 if ((prop = node.property ("source")) == 0) {
1689 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1690 return boost::shared_ptr<AudioRegion>();
1694 PBD::ID s_id (prop->value());
1696 if ((source = source_by_id (s_id)) == 0) {
1697 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1698 return boost::shared_ptr<AudioRegion>();
1701 as = boost::dynamic_pointer_cast<AudioSource>(source);
1703 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1704 return boost::shared_ptr<AudioRegion>();
1707 sources.push_back (as);
1709 /* pickup other channels */
1711 for (uint32_t n=1; n < nchans; ++n) {
1712 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1713 if ((prop = node.property (buf)) != 0) {
1715 PBD::ID id2 (prop->value());
1717 if ((source = source_by_id (id2)) == 0) {
1718 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1719 return boost::shared_ptr<AudioRegion>();
1722 as = boost::dynamic_pointer_cast<AudioSource>(source);
1724 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1725 return boost::shared_ptr<AudioRegion>();
1727 sources.push_back (as);
1731 for (uint32_t n = 0; n < nchans; ++n) {
1732 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1733 if ((prop = node.property (buf)) != 0) {
1735 PBD::ID id2 (prop->value());
1737 if ((source = source_by_id (id2)) == 0) {
1738 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1739 return boost::shared_ptr<AudioRegion>();
1742 as = boost::dynamic_pointer_cast<AudioSource>(source);
1744 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1745 return boost::shared_ptr<AudioRegion>();
1747 master_sources.push_back (as);
1752 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1754 /* a final detail: this is the one and only place that we know how long missing files are */
1756 if (region->whole_file()) {
1757 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1758 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1760 sfp->set_length (region->length());
1765 if (!master_sources.empty()) {
1766 if (master_sources.size() != nchans) {
1767 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1769 region->set_master_sources (master_sources);
1777 catch (failed_constructor& err) {
1778 return boost::shared_ptr<AudioRegion>();
1782 boost::shared_ptr<MidiRegion>
1783 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1785 const XMLProperty* prop;
1786 boost::shared_ptr<Source> source;
1787 boost::shared_ptr<MidiSource> ms;
1790 if (node.name() != X_("Region")) {
1791 return boost::shared_ptr<MidiRegion>();
1794 if ((prop = node.property ("name")) == 0) {
1795 cerr << "no name for this region\n";
1799 if ((prop = node.property (X_("source-0"))) == 0) {
1800 if ((prop = node.property ("source")) == 0) {
1801 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1802 return boost::shared_ptr<MidiRegion>();
1806 PBD::ID s_id (prop->value());
1808 if ((source = source_by_id (s_id)) == 0) {
1809 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1810 return boost::shared_ptr<MidiRegion>();
1813 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1815 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1816 return boost::shared_ptr<MidiRegion>();
1819 sources.push_back (ms);
1822 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1823 /* a final detail: this is the one and only place that we know how long missing files are */
1825 if (region->whole_file()) {
1826 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1827 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1829 sfp->set_length (region->length());
1837 catch (failed_constructor& err) {
1838 return boost::shared_ptr<MidiRegion>();
1843 Session::get_sources_as_xml ()
1846 XMLNode* node = new XMLNode (X_("Sources"));
1847 Glib::Threads::Mutex::Lock lm (source_lock);
1849 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1850 node->add_child_nocopy (i->second->get_state());
1857 Session::reset_write_sources (bool mark_write_complete, bool force)
1859 boost::shared_ptr<RouteList> rl = routes.reader();
1860 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1861 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1864 // block state saving
1865 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1866 tr->reset_write_sources(mark_write_complete, force);
1867 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1873 Session::load_sources (const XMLNode& node)
1876 XMLNodeConstIterator niter;
1877 boost::shared_ptr<Source> source; /* don't need this but it stops some
1878 * versions of gcc complaining about
1879 * discarded return values.
1882 nlist = node.children();
1886 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1889 if ((source = XMLSourceFactory (**niter)) == 0) {
1890 error << _("Session: cannot create Source from XML description.") << endmsg;
1893 } catch (MissingSource& err) {
1897 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1898 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1899 PROGRAM_NAME) << endmsg;
1903 if (!no_questions_about_missing_files) {
1904 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1909 switch (user_choice) {
1911 /* user added a new search location, so try again */
1916 /* user asked to quit the entire session load
1921 no_questions_about_missing_files = true;
1925 no_questions_about_missing_files = true;
1932 case DataType::AUDIO:
1933 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1936 case DataType::MIDI:
1937 /* The MIDI file is actually missing so
1938 * just create a new one in the same
1939 * location. Do not announce its
1943 if (!Glib::path_is_absolute (err.path)) {
1944 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
1946 /* this should be an unrecoverable error: we would be creating a MIDI file outside
1951 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
1952 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
1953 /* reset ID to match the missing one */
1954 source->set_id (**niter);
1955 /* Now we can announce it */
1956 SourceFactory::SourceCreated (source);
1967 boost::shared_ptr<Source>
1968 Session::XMLSourceFactory (const XMLNode& node)
1970 if (node.name() != "Source") {
1971 return boost::shared_ptr<Source>();
1975 /* note: do peak building in another thread when loading session state */
1976 return SourceFactory::create (*this, node, true);
1979 catch (failed_constructor& err) {
1980 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
1981 return boost::shared_ptr<Source>();
1986 Session::save_template (string template_name)
1988 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
1992 bool absolute_path = Glib::path_is_absolute (template_name);
1994 /* directory to put the template in */
1995 std::string template_dir_path;
1997 if (!absolute_path) {
1998 std::string user_template_dir(user_template_directory());
2000 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2001 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2002 user_template_dir, g_strerror (errno)) << endmsg;
2006 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2008 template_dir_path = template_name;
2011 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2012 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2013 template_dir_path) << endmsg;
2017 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2018 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2019 template_dir_path, g_strerror (errno)) << endmsg;
2024 std::string template_file_path;
2025 if (absolute_path) {
2026 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2028 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2031 SessionSaveUnderway (); /* EMIT SIGNAL */
2035 tree.set_root (&get_template());
2036 if (!tree.write (template_file_path)) {
2037 error << _("template not saved") << endmsg;
2041 /* copy plugin state directory */
2043 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2045 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2046 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2047 template_plugin_state_path, g_strerror (errno)) << endmsg;
2051 copy_recurse (plugins_dir(), template_plugin_state_path);
2057 Session::refresh_disk_space ()
2059 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2061 Glib::Threads::Mutex::Lock lm (space_lock);
2063 /* get freespace on every FS that is part of the session path */
2065 _total_free_4k_blocks = 0;
2066 _total_free_4k_blocks_uncertain = false;
2068 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2070 struct statfs statfsbuf;
2071 statfs (i->path.c_str(), &statfsbuf);
2073 double const scale = statfsbuf.f_bsize / 4096.0;
2075 /* See if this filesystem is read-only */
2076 struct statvfs statvfsbuf;
2077 statvfs (i->path.c_str(), &statvfsbuf);
2079 /* f_bavail can be 0 if it is undefined for whatever
2080 filesystem we are looking at; Samba shares mounted
2081 via GVFS are an example of this.
2083 if (statfsbuf.f_bavail == 0) {
2084 /* block count unknown */
2086 i->blocks_unknown = true;
2087 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2088 /* read-only filesystem */
2090 i->blocks_unknown = false;
2092 /* read/write filesystem with known space */
2093 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2094 i->blocks_unknown = false;
2097 _total_free_4k_blocks += i->blocks;
2098 if (i->blocks_unknown) {
2099 _total_free_4k_blocks_uncertain = true;
2102 #elif defined PLATFORM_WINDOWS
2103 vector<string> scanned_volumes;
2104 vector<string>::iterator j;
2105 vector<space_and_path>::iterator i;
2106 DWORD nSectorsPerCluster, nBytesPerSector,
2107 nFreeClusters, nTotalClusters;
2111 _total_free_4k_blocks = 0;
2113 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2114 strncpy (disk_drive, (*i).path.c_str(), 3);
2118 volume_found = false;
2119 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2121 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2122 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2123 i->blocks = (uint32_t)(nFreeBytes / 4096);
2125 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2126 if (0 == j->compare(disk_drive)) {
2127 volume_found = true;
2132 if (!volume_found) {
2133 scanned_volumes.push_back(disk_drive);
2134 _total_free_4k_blocks += i->blocks;
2139 if (0 == _total_free_4k_blocks) {
2140 strncpy (disk_drive, path().c_str(), 3);
2143 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2145 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2146 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2147 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2154 Session::get_best_session_directory_for_new_audio ()
2156 vector<space_and_path>::iterator i;
2157 string result = _session_dir->root_path();
2159 /* handle common case without system calls */
2161 if (session_dirs.size() == 1) {
2165 /* OK, here's the algorithm we're following here:
2167 We want to select which directory to use for
2168 the next file source to be created. Ideally,
2169 we'd like to use a round-robin process so as to
2170 get maximum performance benefits from splitting
2171 the files across multiple disks.
2173 However, in situations without much diskspace, an
2174 RR approach may end up filling up a filesystem
2175 with new files while others still have space.
2176 Its therefore important to pay some attention to
2177 the freespace in the filesystem holding each
2178 directory as well. However, if we did that by
2179 itself, we'd keep creating new files in the file
2180 system with the most space until it was as full
2181 as all others, thus negating any performance
2182 benefits of this RAID-1 like approach.
2184 So, we use a user-configurable space threshold. If
2185 there are at least 2 filesystems with more than this
2186 much space available, we use RR selection between them.
2187 If not, then we pick the filesystem with the most space.
2189 This gets a good balance between the two
2193 refresh_disk_space ();
2195 int free_enough = 0;
2197 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2198 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2203 if (free_enough >= 2) {
2204 /* use RR selection process, ensuring that the one
2208 i = last_rr_session_dir;
2211 if (++i == session_dirs.end()) {
2212 i = session_dirs.begin();
2215 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2216 SessionDirectory sdir(i->path);
2217 if (sdir.create ()) {
2219 last_rr_session_dir = i;
2224 } while (i != last_rr_session_dir);
2228 /* pick FS with the most freespace (and that
2229 seems to actually work ...)
2232 vector<space_and_path> sorted;
2233 space_and_path_ascending_cmp cmp;
2235 sorted = session_dirs;
2236 sort (sorted.begin(), sorted.end(), cmp);
2238 for (i = sorted.begin(); i != sorted.end(); ++i) {
2239 SessionDirectory sdir(i->path);
2240 if (sdir.create ()) {
2242 last_rr_session_dir = i;
2252 Session::automation_dir () const
2254 return Glib::build_filename (_path, "automation");
2258 Session::analysis_dir () const
2260 return Glib::build_filename (_path, "analysis");
2264 Session::plugins_dir () const
2266 return Glib::build_filename (_path, "plugins");
2270 Session::externals_dir () const
2272 return Glib::build_filename (_path, "externals");
2276 Session::load_bundles (XMLNode const & node)
2278 XMLNodeList nlist = node.children();
2279 XMLNodeConstIterator niter;
2283 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2284 if ((*niter)->name() == "InputBundle") {
2285 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2286 } else if ((*niter)->name() == "OutputBundle") {
2287 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2289 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2298 Session::load_route_groups (const XMLNode& node, int version)
2300 XMLNodeList nlist = node.children();
2301 XMLNodeConstIterator niter;
2305 if (version >= 3000) {
2307 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2308 if ((*niter)->name() == "RouteGroup") {
2309 RouteGroup* rg = new RouteGroup (*this, "");
2310 add_route_group (rg);
2311 rg->set_state (**niter, version);
2315 } else if (version < 3000) {
2317 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2318 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2319 RouteGroup* rg = new RouteGroup (*this, "");
2320 add_route_group (rg);
2321 rg->set_state (**niter, version);
2330 state_file_filter (const string &str, void* /*arg*/)
2332 return (str.length() > strlen(statefile_suffix) &&
2333 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2337 remove_end(string state)
2339 string statename(state);
2341 string::size_type start,end;
2342 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2343 statename = statename.substr (start+1);
2346 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2347 end = statename.length();
2350 return string(statename.substr (0, end));
2354 Session::possible_states (string path)
2356 vector<string> states;
2357 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2359 transform(states.begin(), states.end(), states.begin(), remove_end);
2361 sort (states.begin(), states.end());
2367 Session::possible_states () const
2369 return possible_states(_path);
2373 Session::add_route_group (RouteGroup* g)
2375 _route_groups.push_back (g);
2376 route_group_added (g); /* EMIT SIGNAL */
2378 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2379 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2380 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2386 Session::remove_route_group (RouteGroup& rg)
2388 list<RouteGroup*>::iterator i;
2390 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2391 _route_groups.erase (i);
2394 route_group_removed (); /* EMIT SIGNAL */
2398 /** Set a new order for our route groups, without adding or removing any.
2399 * @param groups Route group list in the new order.
2402 Session::reorder_route_groups (list<RouteGroup*> groups)
2404 _route_groups = groups;
2406 route_groups_reordered (); /* EMIT SIGNAL */
2412 Session::route_group_by_name (string name)
2414 list<RouteGroup *>::iterator i;
2416 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2417 if ((*i)->name() == name) {
2425 Session::all_route_group() const
2427 return *_all_route_group;
2431 Session::add_commands (vector<Command*> const & cmds)
2433 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2439 Session::begin_reversible_command (const string& name)
2441 begin_reversible_command (g_quark_from_string (name.c_str ()));
2444 /** Begin a reversible command using a GQuark to identify it.
2445 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2446 * but there must be as many begin...()s as there are commit...()s.
2449 Session::begin_reversible_command (GQuark q)
2451 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2452 to hold all the commands that are committed. This keeps the order of
2453 commands correct in the history.
2456 if (_current_trans == 0) {
2457 /* start a new transaction */
2458 assert (_current_trans_quarks.empty ());
2459 _current_trans = new UndoTransaction();
2460 _current_trans->set_name (g_quark_to_string (q));
2463 _current_trans_quarks.push_front (q);
2467 Session::abort_reversible_command ()
2469 if (_current_trans != 0) {
2470 _current_trans->clear();
2471 delete _current_trans;
2473 _current_trans_quarks.clear();
2478 Session::commit_reversible_command (Command *cmd)
2480 assert (_current_trans);
2481 assert (!_current_trans_quarks.empty ());
2486 _current_trans->add_command (cmd);
2489 _current_trans_quarks.pop_front ();
2491 if (!_current_trans_quarks.empty ()) {
2492 /* the transaction we're committing is not the top-level one */
2496 if (_current_trans->empty()) {
2497 /* no commands were added to the transaction, so just get rid of it */
2498 delete _current_trans;
2503 gettimeofday (&now, 0);
2504 _current_trans->set_timestamp (now);
2506 _history.add (_current_trans);
2511 accept_all_audio_files (const string& path, void* /*arg*/)
2513 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2517 if (!AudioFileSource::safe_audio_file_extension (path)) {
2525 accept_all_midi_files (const string& path, void* /*arg*/)
2527 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2531 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2532 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2533 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2537 accept_all_state_files (const string& path, void* /*arg*/)
2539 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2543 std::string const statefile_ext (statefile_suffix);
2544 if (path.length() >= statefile_ext.length()) {
2545 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2552 Session::find_all_sources (string path, set<string>& result)
2557 if (!tree.read (path)) {
2561 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2566 XMLNodeConstIterator niter;
2568 nlist = node->children();
2572 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2576 if ((prop = (*niter)->property (X_("type"))) == 0) {
2580 DataType type (prop->value());
2582 if ((prop = (*niter)->property (X_("name"))) == 0) {
2586 if (Glib::path_is_absolute (prop->value())) {
2587 /* external file, ignore */
2595 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2596 result.insert (found_path);
2604 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2606 vector<string> state_files;
2608 string this_snapshot_path;
2614 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2615 ripped = ripped.substr (0, ripped.length() - 1);
2618 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2620 if (state_files.empty()) {
2625 this_snapshot_path = _path;
2626 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2627 this_snapshot_path += statefile_suffix;
2629 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2631 if (exclude_this_snapshot && *i == this_snapshot_path) {
2635 if (find_all_sources (*i, result) < 0) {
2643 struct RegionCounter {
2644 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2645 AudioSourceList::iterator iter;
2646 boost::shared_ptr<Region> region;
2649 RegionCounter() : count (0) {}
2653 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2655 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2656 return r.get_value_or (1);
2660 Session::cleanup_regions ()
2662 bool removed = false;
2663 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2665 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2667 uint32_t used = playlists->region_use_count (i->second);
2669 if (used == 0 && !i->second->automatic ()) {
2671 RegionFactory::map_remove (i->second);
2676 // re-check to remove parent references of compound regions
2677 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2678 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2681 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2682 if (0 == playlists->region_use_count (i->second)) {
2683 RegionFactory::map_remove (i->second);
2688 /* dump the history list */
2695 Session::cleanup_sources (CleanupReport& rep)
2697 // FIXME: needs adaptation to midi
2699 vector<boost::shared_ptr<Source> > dead_sources;
2702 vector<string> candidates;
2703 vector<string> unused;
2704 set<string> all_sources;
2713 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2715 /* consider deleting all unused playlists */
2717 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2722 /* sync the "all regions" property of each playlist with its current state
2725 playlists->sync_all_regions_with_regions ();
2727 /* find all un-used sources */
2732 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2734 SourceMap::iterator tmp;
2739 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2743 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2744 dead_sources.push_back (i->second);
2745 i->second->drop_references ();
2751 /* build a list of all the possible audio directories for the session */
2753 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2754 SessionDirectory sdir ((*i).path);
2755 asp += sdir.sound_path();
2757 audio_path += asp.to_string();
2760 /* build a list of all the possible midi directories for the session */
2762 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2763 SessionDirectory sdir ((*i).path);
2764 msp += sdir.midi_path();
2766 midi_path += msp.to_string();
2768 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2769 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2771 /* find all sources, but don't use this snapshot because the
2772 state file on disk still references sources we may have already
2776 find_all_sources_across_snapshots (all_sources, true);
2778 /* add our current source list
2781 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2782 boost::shared_ptr<FileSource> fs;
2783 SourceMap::iterator tmp = i;
2786 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2788 if (!fs->is_stub()) {
2790 if (playlists->source_use_count (fs) != 0) {
2791 all_sources.insert (fs->path());
2794 /* we might not remove this source from disk, because it may be used
2795 by other snapshots, but its not being used in this version
2796 so lets get rid of it now, along with any representative regions
2800 RegionFactory::remove_regions_using_source (i->second);
2803 // also remove source from all_sources
2805 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2806 spath = Glib::path_get_basename (*j);
2807 if ( spath == i->second->name () ) {
2808 all_sources.erase (j);
2819 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2824 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2826 tmppath1 = canonical_path (spath);
2827 tmppath2 = canonical_path ((*i));
2829 if (tmppath1 == tmppath2) {
2836 unused.push_back (spath);
2840 /* now try to move all unused files into the "dead" directory(ies) */
2842 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2843 struct stat statbuf;
2847 /* don't move the file across filesystems, just
2848 stick it in the `dead_dir_name' directory
2849 on whichever filesystem it was already on.
2852 if ((*x).find ("/sounds/") != string::npos) {
2854 /* old school, go up 1 level */
2856 newpath = Glib::path_get_dirname (*x); // "sounds"
2857 newpath = Glib::path_get_dirname (newpath); // "session-name"
2861 /* new school, go up 4 levels */
2863 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2864 newpath = Glib::path_get_dirname (newpath); // "session-name"
2865 newpath = Glib::path_get_dirname (newpath); // "interchange"
2866 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2869 newpath = Glib::build_filename (newpath, dead_dir_name);
2871 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2872 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2876 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2878 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2880 /* the new path already exists, try versioning */
2882 char buf[PATH_MAX+1];
2886 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2889 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2890 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2894 if (version == 999) {
2895 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2899 newpath = newpath_v;
2904 /* it doesn't exist, or we can't read it or something */
2908 stat ((*x).c_str(), &statbuf);
2910 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2911 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2912 (*x), newpath, strerror (errno))
2917 /* see if there an easy to find peakfile for this file, and remove it.
2920 string base = basename_nosuffix (*x);
2921 base += "%A"; /* this is what we add for the channel suffix of all native files,
2922 or for the first channel of embedded files. it will miss
2923 some peakfiles for other channels
2925 string peakpath = peak_path (base);
2927 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2928 if (::g_unlink (peakpath.c_str()) != 0) {
2929 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2930 peakpath, _path, strerror (errno))
2932 /* try to back out */
2933 ::rename (newpath.c_str(), _path.c_str());
2938 rep.paths.push_back (*x);
2939 rep.space += statbuf.st_size;
2942 /* dump the history list */
2946 /* save state so we don't end up a session file
2947 referring to non-existent sources.
2954 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2960 Session::cleanup_trash_sources (CleanupReport& rep)
2962 // FIXME: needs adaptation for MIDI
2964 vector<space_and_path>::iterator i;
2970 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2972 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2974 clear_directory (dead_dir, &rep.space, &rep.paths);
2981 Session::set_dirty ()
2983 /* never mark session dirty during loading */
2985 if (_state_of_the_state & Loading) {
2989 bool was_dirty = dirty();
2991 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2995 DirtyChanged(); /* EMIT SIGNAL */
3001 Session::set_clean ()
3003 bool was_dirty = dirty();
3005 _state_of_the_state = Clean;
3009 DirtyChanged(); /* EMIT SIGNAL */
3014 Session::set_deletion_in_progress ()
3016 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3020 Session::clear_deletion_in_progress ()
3022 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3026 Session::add_controllable (boost::shared_ptr<Controllable> c)
3028 /* this adds a controllable to the list managed by the Session.
3029 this is a subset of those managed by the Controllable class
3030 itself, and represents the only ones whose state will be saved
3031 as part of the session.
3034 Glib::Threads::Mutex::Lock lm (controllables_lock);
3035 controllables.insert (c);
3038 struct null_deleter { void operator()(void const *) const {} };
3041 Session::remove_controllable (Controllable* c)
3043 if (_state_of_the_state & Deletion) {
3047 Glib::Threads::Mutex::Lock lm (controllables_lock);
3049 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3051 if (x != controllables.end()) {
3052 controllables.erase (x);
3056 boost::shared_ptr<Controllable>
3057 Session::controllable_by_id (const PBD::ID& id)
3059 Glib::Threads::Mutex::Lock lm (controllables_lock);
3061 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3062 if ((*i)->id() == id) {
3067 return boost::shared_ptr<Controllable>();
3070 boost::shared_ptr<Controllable>
3071 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3073 boost::shared_ptr<Controllable> c;
3074 boost::shared_ptr<Route> r;
3076 switch (desc.top_level_type()) {
3077 case ControllableDescriptor::NamedRoute:
3079 std::string str = desc.top_level_name();
3080 if (str == "Master" || str == "master") {
3082 } else if (str == "control" || str == "listen") {
3085 r = route_by_name (desc.top_level_name());
3090 case ControllableDescriptor::RemoteControlID:
3091 r = route_by_remote_id (desc.rid());
3099 switch (desc.subtype()) {
3100 case ControllableDescriptor::Gain:
3101 c = r->gain_control ();
3104 case ControllableDescriptor::Trim:
3105 c = r->trim()->gain_control ();
3108 case ControllableDescriptor::Solo:
3109 c = r->solo_control();
3112 case ControllableDescriptor::Mute:
3113 c = r->mute_control();
3116 case ControllableDescriptor::Recenable:
3118 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3121 c = t->rec_enable_control ();
3126 case ControllableDescriptor::PanDirection:
3128 c = r->pannable()->pan_azimuth_control;
3132 case ControllableDescriptor::PanWidth:
3134 c = r->pannable()->pan_width_control;
3138 case ControllableDescriptor::PanElevation:
3140 c = r->pannable()->pan_elevation_control;
3144 case ControllableDescriptor::Balance:
3145 /* XXX simple pan control */
3148 case ControllableDescriptor::PluginParameter:
3150 uint32_t plugin = desc.target (0);
3151 uint32_t parameter_index = desc.target (1);
3153 /* revert to zero based counting */
3159 if (parameter_index > 0) {
3163 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3166 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3167 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3172 case ControllableDescriptor::SendGain:
3174 uint32_t send = desc.target (0);
3176 /* revert to zero-based counting */
3182 boost::shared_ptr<Processor> p = r->nth_send (send);
3185 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3186 boost::shared_ptr<Amp> a = s->amp();
3189 c = s->amp()->gain_control();
3196 /* relax and return a null pointer */
3204 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3207 Stateful::add_instant_xml (node, _path);
3210 if (write_to_config) {
3211 Config->add_instant_xml (node);
3216 Session::instant_xml (const string& node_name)
3218 return Stateful::instant_xml (node_name, _path);
3222 Session::save_history (string snapshot_name)
3230 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3231 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3235 if (snapshot_name.empty()) {
3236 snapshot_name = _current_snapshot_name;
3239 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3240 const string backup_filename = history_filename + backup_suffix;
3241 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3242 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3244 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3245 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3246 error << _("could not backup old history file, current history not saved") << endmsg;
3251 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3253 if (!tree.write (xml_path))
3255 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3257 if (g_remove (xml_path.c_str()) != 0) {
3258 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3259 xml_path, g_strerror (errno)) << endmsg;
3261 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3262 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3263 backup_path, g_strerror (errno)) << endmsg;
3273 Session::restore_history (string snapshot_name)
3277 if (snapshot_name.empty()) {
3278 snapshot_name = _current_snapshot_name;
3281 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3282 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3284 info << "Loading history from " << xml_path << endmsg;
3286 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3287 info << string_compose (_("%1: no history file \"%2\" for this session."),
3288 _name, xml_path) << endmsg;
3292 if (!tree.read (xml_path)) {
3293 error << string_compose (_("Could not understand session history file \"%1\""),
3294 xml_path) << endmsg;
3301 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3304 UndoTransaction* ut = new UndoTransaction ();
3307 ut->set_name(t->property("name")->value());
3308 stringstream ss(t->property("tv-sec")->value());
3310 ss.str(t->property("tv-usec")->value());
3312 ut->set_timestamp(tv);
3314 for (XMLNodeConstIterator child_it = t->children().begin();
3315 child_it != t->children().end(); child_it++)
3317 XMLNode *n = *child_it;
3320 if (n->name() == "MementoCommand" ||
3321 n->name() == "MementoUndoCommand" ||
3322 n->name() == "MementoRedoCommand") {
3324 if ((c = memento_command_factory(n))) {
3328 } else if (n->name() == "NoteDiffCommand") {
3329 PBD::ID id (n->property("midi-source")->value());
3330 boost::shared_ptr<MidiSource> midi_source =
3331 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3333 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3335 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3338 } else if (n->name() == "SysExDiffCommand") {
3340 PBD::ID id (n->property("midi-source")->value());
3341 boost::shared_ptr<MidiSource> midi_source =
3342 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3344 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3346 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3349 } else if (n->name() == "PatchChangeDiffCommand") {
3351 PBD::ID id (n->property("midi-source")->value());
3352 boost::shared_ptr<MidiSource> midi_source =
3353 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3355 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3357 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3360 } else if (n->name() == "StatefulDiffCommand") {
3361 if ((c = stateful_diff_command_factory (n))) {
3362 ut->add_command (c);
3365 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3376 Session::config_changed (std::string p, bool ours)
3382 if (p == "seamless-loop") {
3384 } else if (p == "rf-speed") {
3386 } else if (p == "auto-loop") {
3388 } else if (p == "auto-input") {
3390 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3391 /* auto-input only makes a difference if we're rolling */
3392 set_track_monitor_input_status (!config.get_auto_input());
3395 } else if (p == "punch-in") {
3399 if ((location = _locations->auto_punch_location()) != 0) {
3401 if (config.get_punch_in ()) {
3402 replace_event (SessionEvent::PunchIn, location->start());
3404 remove_event (location->start(), SessionEvent::PunchIn);
3408 } else if (p == "punch-out") {
3412 if ((location = _locations->auto_punch_location()) != 0) {
3414 if (config.get_punch_out()) {
3415 replace_event (SessionEvent::PunchOut, location->end());
3417 clear_events (SessionEvent::PunchOut);
3421 } else if (p == "edit-mode") {
3423 Glib::Threads::Mutex::Lock lm (playlists->lock);
3425 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3426 (*i)->set_edit_mode (Config->get_edit_mode ());
3429 } else if (p == "use-video-sync") {
3431 waiting_for_sync_offset = config.get_use_video_sync();
3433 } else if (p == "mmc-control") {
3435 //poke_midi_thread ();
3437 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3439 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3441 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3443 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3445 } else if (p == "midi-control") {
3447 //poke_midi_thread ();
3449 } else if (p == "raid-path") {
3451 setup_raid_path (config.get_raid_path());
3453 } else if (p == "timecode-format") {
3457 } else if (p == "video-pullup") {
3461 } else if (p == "seamless-loop") {
3463 if (play_loop && transport_rolling()) {
3464 // to reset diskstreams etc
3465 request_play_loop (true);
3468 } else if (p == "rf-speed") {
3470 cumulative_rf_motion = 0;
3473 } else if (p == "click-sound") {
3475 setup_click_sounds (1);
3477 } else if (p == "click-emphasis-sound") {
3479 setup_click_sounds (-1);
3481 } else if (p == "clicking") {
3483 if (Config->get_clicking()) {
3484 if (_click_io && click_data) { // don't require emphasis data
3491 } else if (p == "click-gain") {
3494 _click_gain->set_gain (Config->get_click_gain(), this);
3497 } else if (p == "send-mtc") {
3499 if (Config->get_send_mtc ()) {
3500 /* mark us ready to send */
3501 next_quarter_frame_to_send = 0;
3504 } else if (p == "send-mmc") {
3506 _mmc->enable_send (Config->get_send_mmc ());
3508 } else if (p == "midi-feedback") {
3510 session_midi_feedback = Config->get_midi_feedback();
3512 } else if (p == "jack-time-master") {
3514 engine().reset_timebase ();
3516 } else if (p == "native-file-header-format") {
3518 if (!first_file_header_format_reset) {
3519 reset_native_file_format ();
3522 first_file_header_format_reset = false;
3524 } else if (p == "native-file-data-format") {
3526 if (!first_file_data_format_reset) {
3527 reset_native_file_format ();
3530 first_file_data_format_reset = false;
3532 } else if (p == "external-sync") {
3533 if (!config.get_external_sync()) {
3534 drop_sync_source ();
3536 switch_to_sync_source (Config->get_sync_source());
3538 } else if (p == "denormal-model") {
3540 } else if (p == "history-depth") {
3541 set_history_depth (Config->get_history_depth());
3542 } else if (p == "remote-model") {
3543 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3546 } else if (p == "initial-program-change") {
3548 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3551 buf[0] = MIDI::program; // channel zero by default
3552 buf[1] = (Config->get_initial_program_change() & 0x7f);
3554 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3556 } else if (p == "solo-mute-override") {
3557 // catch_up_on_solo_mute_override ();
3558 } else if (p == "listen-position" || p == "pfl-position") {
3559 listen_position_changed ();
3560 } else if (p == "solo-control-is-listen-control") {
3561 solo_control_mode_changed ();
3562 } else if (p == "solo-mute-gain") {
3563 _solo_cut_control->Changed();
3564 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3565 last_timecode_valid = false;
3566 } else if (p == "playback-buffer-seconds") {
3567 AudioSource::allocate_working_buffers (frame_rate());
3568 } else if (p == "ltc-source-port") {
3569 reconnect_ltc_input ();
3570 } else if (p == "ltc-sink-port") {
3571 reconnect_ltc_output ();
3572 } else if (p == "timecode-generator-offset") {
3573 ltc_tx_parse_offset();
3580 Session::set_history_depth (uint32_t d)
3582 _history.set_depth (d);
3586 Session::load_diskstreams_2X (XMLNode const & node, int)
3589 XMLNodeConstIterator citer;
3591 clist = node.children();
3593 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3596 /* diskstreams added automatically by DiskstreamCreated handler */
3597 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3598 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3599 _diskstreams_2X.push_back (dsp);
3601 error << _("Session: unknown diskstream type in XML") << endmsg;
3605 catch (failed_constructor& err) {
3606 error << _("Session: could not load diskstream via XML state") << endmsg;
3614 /** Connect things to the MMC object */
3616 Session::setup_midi_machine_control ()
3618 _mmc = new MIDI::MachineControl;
3619 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3621 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3622 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3623 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3624 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3625 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3626 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3627 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3628 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3629 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3630 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3631 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3632 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3633 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3635 /* also handle MIDI SPP because its so common */
3637 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3638 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3639 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3642 boost::shared_ptr<Controllable>
3643 Session::solo_cut_control() const
3645 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3646 controls in Ardour that currently get presented to the user in the GUI that require
3647 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3649 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3650 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3654 return _solo_cut_control;
3658 Session::rename (const std::string& new_name)
3660 string legal_name = legalize_for_path (new_name);
3666 string const old_sources_root = _session_dir->sources_root();
3668 if (!_writable || (_state_of_the_state & CannotSave)) {
3669 error << _("Cannot rename read-only session.") << endmsg;
3670 return 0; // don't show "messed up" warning
3672 if (record_status() == Recording) {
3673 error << _("Cannot rename session while recording") << endmsg;
3674 return 0; // don't show "messed up" warning
3677 StateProtector stp (this);
3682 * interchange subdirectory
3686 * Backup files are left unchanged and not renamed.
3689 /* Windows requires that we close all files before attempting the
3690 * rename. This works on other platforms, but isn't necessary there.
3691 * Leave it in place for all platforms though, since it may help
3692 * catch issues that could arise if the way Source files work ever
3693 * change (since most developers are not using Windows).
3696 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3697 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3703 /* pass one: not 100% safe check that the new directory names don't
3707 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3711 /* this is a stupid hack because Glib::path_get_dirname() is
3712 * lexical-only, and so passing it /a/b/c/ gives a different
3713 * result than passing it /a/b/c ...
3716 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3717 oldstr = oldstr.substr (0, oldstr.length() - 1);
3720 string base = Glib::path_get_dirname (oldstr);
3722 newstr = Glib::build_filename (base, legal_name);
3724 cerr << "Looking for " << newstr << endl;
3726 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3727 cerr << " exists\n";
3736 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3742 /* this is a stupid hack because Glib::path_get_dirname() is
3743 * lexical-only, and so passing it /a/b/c/ gives a different
3744 * result than passing it /a/b/c ...
3747 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3748 oldstr = oldstr.substr (0, oldstr.length() - 1);
3751 string base = Glib::path_get_dirname (oldstr);
3752 newstr = Glib::build_filename (base, legal_name);
3754 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3756 cerr << "Rename " << oldstr << " => " << newstr << endl;
3757 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3758 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3759 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3763 /* Reset path in "session dirs" */
3768 /* reset primary SessionDirectory object */
3771 (*_session_dir) = newstr;
3776 /* now rename directory below session_dir/interchange */
3778 string old_interchange_dir;
3779 string new_interchange_dir;
3781 /* use newstr here because we renamed the path
3782 * (folder/directory) that used to be oldstr to newstr above
3785 v.push_back (newstr);
3786 v.push_back (interchange_dir_name);
3787 v.push_back (Glib::path_get_basename (oldstr));
3789 old_interchange_dir = Glib::build_filename (v);
3792 v.push_back (newstr);
3793 v.push_back (interchange_dir_name);
3794 v.push_back (legal_name);
3796 new_interchange_dir = Glib::build_filename (v);
3798 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3800 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3801 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3802 old_interchange_dir, new_interchange_dir,
3805 error << string_compose (_("renaming %s as %2 failed (%3)"),
3806 old_interchange_dir, new_interchange_dir,
3815 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3816 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3818 cerr << "Rename " << oldstr << " => " << newstr << endl;
3820 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3821 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3822 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3828 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3830 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3831 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3833 cerr << "Rename " << oldstr << " => " << newstr << endl;
3835 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3836 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3837 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3842 /* remove old name from recent sessions */
3843 remove_recent_sessions (_path);
3846 /* update file source paths */
3848 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3849 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3851 string p = fs->path ();
3852 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3854 SourceFactory::setup_peakfile(i->second, true);
3858 _current_snapshot_name = new_name;
3863 /* save state again to get everything just right */
3865 save_state (_current_snapshot_name);
3867 /* add to recent sessions */
3869 store_recent_sessions (new_name, _path);
3875 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3877 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3881 if (!tree.read (xmlpath)) {
3889 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3892 bool found_sr = false;
3893 bool found_data_format = false;
3895 if (get_session_info_from_path (tree, xmlpath)) {
3901 const XMLProperty* prop;
3902 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3903 sample_rate = atoi (prop->value());
3907 const XMLNodeList& children (tree.root()->children());
3908 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3909 const XMLNode* child = *c;
3910 if (child->name() == "Config") {
3911 const XMLNodeList& options (child->children());
3912 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3913 const XMLNode* option = *oc;
3914 const XMLProperty* name = option->property("name");
3920 if (name->value() == "native-file-data-format") {
3921 const XMLProperty* value = option->property ("value");
3923 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3925 found_data_format = true;
3931 if (found_data_format) {
3936 return !(found_sr && found_data_format); // zero if they are both found
3939 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
3940 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
3943 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
3947 SourcePathMap source_path_map;
3949 boost::shared_ptr<AudioFileSource> afs;
3954 Glib::Threads::Mutex::Lock lm (source_lock);
3956 cerr << " total sources = " << sources.size();
3958 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3959 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3965 if (fs->within_session()) {
3969 if (source_path_map.find (fs->path()) != source_path_map.end()) {
3970 source_path_map[fs->path()].push_back (fs);
3972 SeveralFileSources v;
3974 source_path_map.insert (make_pair (fs->path(), v));
3980 cerr << " fsources = " << total << endl;
3982 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
3984 /* tell caller where we are */
3986 string old_path = i->first;
3988 callback (n, total, old_path);
3990 cerr << old_path << endl;
3994 switch (i->second.front()->type()) {
3995 case DataType::AUDIO:
3996 new_path = new_audio_source_path_for_embedded (old_path);
3999 case DataType::MIDI:
4000 /* XXX not implemented yet */
4004 if (new_path.empty()) {
4008 cerr << "Move " << old_path << " => " << new_path << endl;
4010 if (!copy_file (old_path, new_path)) {
4011 cerr << "failed !\n";
4015 /* make sure we stop looking in the external
4016 dir/folder. Remember, this is an all-or-nothing
4017 operations, it doesn't merge just some files.
4019 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4021 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4022 (*f)->set_path (new_path);
4027 save_state ("", false, false);
4033 bool accept_all_files (string const &, void *)
4039 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4041 /* It would be good if this did something useful vis-a-vis save-as, but the arguments doesn't provide the correct information right now to do this.
4046 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4048 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4050 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4052 v.push_back (new_session_folder); /* full path */
4053 v.push_back (interchange_dir_name);
4054 v.push_back (new_session_path); /* just one directory/folder */
4055 v.push_back (typedir);
4056 v.push_back (Glib::path_get_basename (old_path));
4058 return Glib::build_filename (v);
4062 Session::save_as (SaveAs& saveas)
4064 vector<string> files;
4065 string current_folder = Glib::path_get_dirname (_path);
4066 string new_folder = legalize_for_path (saveas.new_name);
4067 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4068 int64_t total_bytes = 0;
4072 int32_t internal_file_cnt = 0;
4074 vector<string> do_not_copy_extensions;
4075 do_not_copy_extensions.push_back (statefile_suffix);
4076 do_not_copy_extensions.push_back (pending_suffix);
4077 do_not_copy_extensions.push_back (backup_suffix);
4078 do_not_copy_extensions.push_back (temp_suffix);
4079 do_not_copy_extensions.push_back (history_suffix);
4081 /* get total size */
4083 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4085 /* need to clear this because
4086 * find_files_matching_filter() is cumulative
4091 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4093 all += files.size();
4095 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4097 g_stat ((*i).c_str(), &gsb);
4098 total_bytes += gsb.st_size;
4102 /* save old values so we can switch back if we are not switching to the new session */
4104 string old_path = _path;
4105 string old_name = _name;
4106 string old_snapshot = _current_snapshot_name;
4107 string old_sd = _session_dir->root_path();
4108 vector<string> old_search_path[DataType::num_types];
4109 string old_config_search_path[DataType::num_types];
4111 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4112 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4113 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4114 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4116 /* switch session directory */
4118 (*_session_dir) = to_dir;
4120 /* create new tree */
4122 if (!_session_dir->create()) {
4123 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4128 /* copy all relevant files. Find each location in session_dirs,
4129 * and copy files from there to target.
4132 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4134 /* need to clear this because
4135 * find_files_matching_filter() is cumulative
4140 const size_t prefix_len = (*sd).path.size();
4142 /* Work just on the files within this session dir */
4144 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4146 /* add dir separator to protect against collisions with
4147 * track names (e.g. track named "audiofiles" or
4151 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4152 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4153 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4155 /* copy all the files. Handling is different for media files
4156 than others because of the *silly* subtree we have below the interchange
4157 folder. That really was a bad idea, but I'm not fixing it as part of
4158 implementing ::save_as().
4161 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4163 std::string from = *i;
4165 if ((*i).find (audiofile_dir_string) != string::npos) {
4167 /* audio file: only copy if asked */
4169 if (saveas.include_media && saveas.copy_media) {
4171 string to = make_new_media_path (*i, to_dir, new_folder);
4173 info << "media file copying from " << from << " to " << to << endmsg;
4175 if (!copy_file (from, to)) {
4176 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4180 /* we found media files inside the session folder */
4182 internal_file_cnt++;
4184 } else if ((*i).find (midifile_dir_string) != string::npos) {
4186 /* midi file: always copy unless
4187 * creating an empty new session
4190 if (saveas.include_media) {
4192 string to = make_new_media_path (*i, to_dir, new_folder);
4194 info << "media file copying from " << from << " to " << to << endmsg;
4196 if (!copy_file (from, to)) {
4197 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4201 /* we found media files inside the session folder */
4203 internal_file_cnt++;
4205 } else if ((*i).find (analysis_dir_string) != string::npos) {
4207 /* make sure analysis dir exists in
4208 * new session folder, but we're not
4209 * copying analysis files here, see
4213 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4218 /* normal non-media file. Don't copy state, history, etc.
4221 bool do_copy = true;
4223 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4224 if (((*i).length() > (*v).length()) && ((*i).find (*v) == (*i).length() - (*v).length())) {
4225 /* end of filename matches extension, do not copy file */
4231 if (!saveas.copy_media && (*i).find (peakfile_suffix) != string::npos) {
4232 /* don't copy peakfiles if
4233 * we're not copying media
4239 string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
4241 info << "attempting to make directory/folder " << to << endmsg;
4243 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4244 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4247 info << "attempting to copy " << from << " to " << to << endmsg;
4249 if (!copy_file (from, to)) {
4250 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4255 /* measure file size even if we're not going to copy so that our Progress
4256 signals are correct, since we included these do-not-copy files
4257 in the computation of the total size and file count.
4261 g_stat ((*i).c_str(), &gsb);
4262 copied += gsb.st_size;
4265 double fraction = (double) copied / total_bytes;
4267 bool keep_going = true;
4269 if (saveas.copy_media) {
4271 /* no need or expectation of this if
4272 * media is not being copied, because
4273 * it will be fast(ish).
4276 /* tell someone "X percent, file M of N"; M is one-based */
4278 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4286 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4292 /* copy optional folders, if any */
4294 string old = plugins_dir ();
4295 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4296 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4297 copy_files (old, newdir);
4300 old = externals_dir ();
4301 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4302 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4303 copy_files (old, newdir);
4306 old = automation_dir ();
4307 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4308 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4309 copy_files (old, newdir);
4312 if (saveas.include_media) {
4314 if (saveas.copy_media) {
4315 #ifndef PLATFORM_WINDOWS
4316 /* There are problems with analysis files on
4317 * Windows, because they used a colon in their
4318 * names as late as 4.0. Colons are not legal
4319 * under Windows even if NTFS allows them.
4321 * This is a tricky problem to solve so for
4322 * just don't copy these files. They will be
4323 * regenerated as-needed anyway, subject to the
4324 * existing issue that the filenames will be
4325 * rejected by Windows, which is a separate
4326 * problem (though related).
4329 /* only needed if we are copying media, since the
4330 * analysis data refers to media data
4333 old = analysis_dir ();
4334 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4335 string newdir = Glib::build_filename (to_dir, "analysis");
4336 copy_files (old, newdir);
4338 #endif /* PLATFORM_WINDOWS */
4344 _current_snapshot_name = saveas.new_name;
4345 _name = saveas.new_name;
4347 if (saveas.include_media && !saveas.copy_media) {
4349 /* reset search paths of the new session (which we're pretending to be right now) to
4350 include the original session search path, so we can still find all audio.
4353 if (internal_file_cnt) {
4354 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4355 ensure_search_path_includes (*s, DataType::AUDIO);
4358 /* we do not do this for MIDI because we copy
4359 all MIDI files if saveas.include_media is
4365 bool was_dirty = dirty ();
4367 save_state ("", false, false, !saveas.include_media);
4368 save_default_options ();
4370 if (saveas.copy_media && saveas.copy_external) {
4371 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4372 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4376 saveas.final_session_folder_name = _path;
4378 if (!saveas.switch_to) {
4380 /* switch back to the way things were */
4384 _current_snapshot_name = old_snapshot;
4386 (*_session_dir) = old_sd;
4392 if (internal_file_cnt) {
4393 /* reset these to their original values */
4394 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4395 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4400 /* prune session dirs, and update disk space statistics
4405 session_dirs.clear ();
4406 session_dirs.push_back (sp);
4407 refresh_disk_space ();
4409 /* ensure that all existing tracks reset their current capture source paths
4411 reset_write_sources (true, true);
4413 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4414 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4417 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4418 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4424 if (fs->within_session()) {
4425 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4426 fs->set_path (newpath);
4431 } catch (Glib::FileError& e) {
4433 saveas.failure_message = e.what();
4435 /* recursively remove all the directories */
4437 remove_directory (to_dir);
4445 saveas.failure_message = _("unknown reason");
4447 /* recursively remove all the directories */
4449 remove_directory (to_dir);