2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
31 #include <cstdio> /* snprintf(3) ... grrr */
44 #include <sys/param.h>
45 #include <sys/mount.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
53 #include <glib/gstdio.h>
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/boost_debug.h"
67 #include "pbd/basename.h"
68 #include "pbd/controllable_descriptor.h"
69 #include "pbd/enumwriter.h"
70 #include "pbd/error.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/convert.h"
76 #include "pbd/localtime_r.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/playlist_source.h"
101 #include "ardour/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/profile.h"
104 #include "ardour/proxy_controllable.h"
105 #include "ardour/recent_sessions.h"
106 #include "ardour/region_factory.h"
107 #include "ardour/route_group.h"
108 #include "ardour/send.h"
109 #include "ardour/session.h"
110 #include "ardour/session_directory.h"
111 #include "ardour/session_metadata.h"
112 #include "ardour/session_playlists.h"
113 #include "ardour/session_state_utils.h"
114 #include "ardour/silentfilesource.h"
115 #include "ardour/sndfilesource.h"
116 #include "ardour/source_factory.h"
117 #include "ardour/speakers.h"
118 #include "ardour/template_utils.h"
119 #include "ardour/tempo.h"
120 #include "ardour/ticker.h"
121 #include "ardour/user_bundle.h"
123 #include "control_protocol/control_protocol.h"
129 using namespace ARDOUR;
133 Session::pre_engine_init (string fullpath)
135 if (fullpath.empty()) {
137 throw failed_constructor();
140 /* discover canonical fullpath */
142 _path = canonical_path(fullpath);
146 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
148 /* finish initialization that can't be done in a normal C++ constructor
152 timerclear (&last_mmc_step);
153 g_atomic_int_set (&processing_prohibited, 0);
154 g_atomic_int_set (&_record_status, Disabled);
155 g_atomic_int_set (&_playback_load, 100);
156 g_atomic_int_set (&_capture_load, 100);
158 _all_route_group->set_active (true, this);
159 interpolation.add_channel_to (0, 0);
161 if (config.get_use_video_sync()) {
162 waiting_for_sync_offset = true;
164 waiting_for_sync_offset = false;
167 last_rr_session_dir = session_dirs.begin();
169 set_history_depth (Config->get_history_depth());
171 /* default: assume simple stereo speaker configuration */
173 _speakers->setup_default_speakers (2);
175 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
176 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
177 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
178 add_controllable (_solo_cut_control);
180 /* These are all static "per-class" signals */
182 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
183 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
184 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
185 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
186 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
188 /* stop IO objects from doing stuff until we're ready for them */
190 Delivery::disable_panners ();
191 IO::disable_connecting ();
193 AudioFileSource::set_peak_dir (_session_dir->peak_path());
197 Session::post_engine_init ()
199 BootMessage (_("Set block size and sample rate"));
201 set_block_size (_engine.samples_per_cycle());
202 set_frame_rate (_engine.sample_rate());
204 BootMessage (_("Using configuration"));
206 _midi_ports = new MidiPortManager;
208 MIDISceneChanger* msc;
210 _scene_changer = msc = new MIDISceneChanger (*this);
211 msc->set_input_port (scene_input_port());
212 msc->set_output_port (scene_out());
214 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
215 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
217 setup_midi_machine_control ();
219 if (_butler->start_thread()) {
223 if (start_midi_thread ()) {
227 setup_click_sounds (0);
228 setup_midi_control ();
230 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
231 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
234 /* tempo map requires sample rate knowledge */
237 _tempo_map = new TempoMap (_current_frame_rate);
238 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
240 /* MidiClock requires a tempo map */
242 midi_clock = new MidiClockTicker ();
243 midi_clock->set_session (this);
245 /* crossfades require sample rate knowledge */
247 SndFileSource::setup_standard_crossfades (*this, frame_rate());
248 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
250 AudioDiskstream::allocate_working_buffers();
251 refresh_disk_space ();
253 /* we're finally ready to call set_state() ... all objects have
254 * been created, the engine is running.
258 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
262 // set_state() will call setup_raid_path(), but if it's a new session we need
263 // to call setup_raid_path() here.
264 setup_raid_path (_path);
269 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
270 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
272 Config->map_parameters (ff);
273 config.map_parameters (ft);
275 /* Reset all panners */
277 Delivery::reset_panners ();
279 /* this will cause the CPM to instantiate any protocols that are in use
280 * (or mandatory), which will pass it this Session, and then call
281 * set_state() on each instantiated protocol to match stored state.
284 ControlProtocolManager::instance().set_session (this);
286 /* This must be done after the ControlProtocolManager set_session above,
287 as it will set states for ports which the ControlProtocolManager creates.
290 // XXX set state of MIDI::Port's
291 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
293 /* And this must be done after the MIDI::Manager::set_port_states as
294 * it will try to make connections whose details are loaded by set_port_states.
299 /* Let control protocols know that we are now all connected, so they
300 * could start talking to surfaces if they want to.
303 ControlProtocolManager::instance().midi_connectivity_established ();
305 if (_is_new && !no_auto_connect()) {
306 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
307 auto_connect_master_bus ();
310 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
312 /* update latencies */
314 initialize_latencies ();
316 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
317 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
318 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
320 } catch (AudioEngine::PortRegistrationFailure& err) {
321 /* handle this one in a different way than all others, so that its clear what happened */
322 error << err.what() << endmsg;
328 BootMessage (_("Reset Remote Controls"));
330 // send_full_time_code (0);
331 _engine.transport_locate (0);
333 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
334 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
336 MIDI::Name::MidiPatchManager::instance().set_session (this);
339 /* initial program change will be delivered later; see ::config_changed() */
341 _state_of_the_state = Clean;
343 Port::set_connecting_blocked (false);
345 DirtyChanged (); /* EMIT SIGNAL */
349 } else if (state_was_pending) {
351 remove_pending_capture_state ();
352 state_was_pending = false;
359 Session::raid_path () const
361 Searchpath raid_search_path;
363 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
364 raid_search_path += (*i).path;
367 return raid_search_path.to_string ();
371 Session::setup_raid_path (string path)
380 session_dirs.clear ();
382 Searchpath search_path(path);
383 Searchpath sound_search_path;
384 Searchpath midi_search_path;
386 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
388 sp.blocks = 0; // not needed
389 session_dirs.push_back (sp);
391 SessionDirectory sdir(sp.path);
393 sound_search_path += sdir.sound_path ();
394 midi_search_path += sdir.midi_path ();
397 // reset the round-robin soundfile path thingie
398 last_rr_session_dir = session_dirs.begin();
402 Session::path_is_within_session (const std::string& path)
404 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
405 if (PBD::path_is_within (i->path, path)) {
413 Session::ensure_subdirs ()
417 dir = session_directory().peak_path();
419 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
420 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
424 dir = session_directory().sound_path();
426 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
427 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
431 dir = session_directory().midi_path();
433 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
434 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
438 dir = session_directory().dead_path();
440 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
441 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
445 dir = session_directory().export_path();
447 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
448 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
452 dir = analysis_dir ();
454 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
455 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
459 dir = plugins_dir ();
461 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
462 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
466 dir = externals_dir ();
468 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
469 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
476 /** @param session_template directory containing session template, or empty.
477 * Caller must not hold process lock.
480 Session::create (const string& session_template, BusProfile* bus_profile)
482 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
483 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
487 if (ensure_subdirs ()) {
491 _writable = exists_and_writable (_path);
493 if (!session_template.empty()) {
494 std::string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
496 ifstream in(in_path.c_str());
499 /* no need to call legalize_for_path() since the string
500 * in session_template is already a legal path name
502 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
504 ofstream out(out_path.c_str());
510 /* Copy plugin state files from template to new session */
511 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
512 copy_recurse (template_plugins, plugins_dir ());
517 error << string_compose (_("Could not open %1 for writing session template"), out_path)
523 error << string_compose (_("Could not open session template %1 for reading"), in_path)
530 /* set initial start + end point */
532 _state_of_the_state = Clean;
534 /* set up Master Out and Control Out if necessary */
539 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
541 if (bus_profile->master_out_channels) {
542 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
546 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
547 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
550 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
551 r->input()->ensure_io (count, false, this);
552 r->output()->ensure_io (count, false, this);
558 /* prohibit auto-connect to master, because there isn't one */
559 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
563 add_routes (rl, false, false, false);
566 /* this allows the user to override settings with an environment variable.
569 if (no_auto_connect()) {
570 bus_profile->input_ac = AutoConnectOption (0);
571 bus_profile->output_ac = AutoConnectOption (0);
574 Config->set_input_auto_connect (bus_profile->input_ac);
575 Config->set_output_auto_connect (bus_profile->output_ac);
578 if (Config->get_use_monitor_bus() && bus_profile) {
579 add_monitor_section ();
586 Session::maybe_write_autosave()
588 if (dirty() && record_status() != Recording) {
589 save_state("", true);
594 Session::remove_pending_capture_state ()
596 std::string pending_state_file_path(_session_dir->root_path());
598 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
600 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
602 if (g_remove (pending_state_file_path.c_str()) != 0) {
603 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
604 pending_state_file_path, g_strerror (errno)) << endmsg;
608 /** Rename a state file.
609 * @param old_name Old snapshot name.
610 * @param new_name New snapshot name.
613 Session::rename_state (string old_name, string new_name)
615 if (old_name == _current_snapshot_name || old_name == _name) {
616 /* refuse to rename the current snapshot or the "main" one */
620 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
621 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
623 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
624 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
626 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
627 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
628 old_name, new_name, g_strerror(errno)) << endmsg;
632 /** Remove a state file.
633 * @param snapshot_name Snapshot name.
636 Session::remove_state (string snapshot_name)
638 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
639 // refuse to remove the current snapshot or the "main" one
643 std::string xml_path(_session_dir->root_path());
645 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
647 if (!create_backup_file (xml_path)) {
648 // don't remove it if a backup can't be made
649 // create_backup_file will log the error.
654 if (g_remove (xml_path.c_str()) != 0) {
655 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
656 xml_path, g_strerror (errno)) << endmsg;
660 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
662 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
665 std::string xml_path(_session_dir->root_path());
667 /* prevent concurrent saves from different threads */
669 Glib::Threads::Mutex::Lock lm (save_state_lock);
671 if (!_writable || (_state_of_the_state & CannotSave)) {
675 if (g_atomic_int_get(&_suspend_save)) {
679 _save_queued = false;
681 if (!_engine.connected ()) {
682 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
688 /* tell sources we're saving first, in case they write out to a new file
689 * which should be saved with the state rather than the old one */
690 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
692 i->second->session_saved();
693 } catch (Evoral::SMF::FileError& e) {
694 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
698 SessionSaveUnderway (); /* EMIT SIGNAL */
701 tree.set_root (&get_template());
703 tree.set_root (&get_state());
706 if (snapshot_name.empty()) {
707 snapshot_name = _current_snapshot_name;
708 } else if (switch_to_snapshot) {
709 _current_snapshot_name = snapshot_name;
714 /* proper save: use statefile_suffix (.ardour in English) */
716 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
718 /* make a backup copy of the old file */
720 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
721 // create_backup_file will log the error
727 /* pending save: use pending_suffix (.pending in English) */
728 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
731 std::string tmp_path(_session_dir->root_path());
732 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
734 cerr << "actually writing state to " << tmp_path << endl;
736 if (!tree.write (tmp_path)) {
737 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
738 if (g_remove (tmp_path.c_str()) != 0) {
739 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
740 tmp_path, g_strerror (errno)) << endmsg;
746 cerr << "renaming state to " << xml_path << endl;
748 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
749 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
750 tmp_path, xml_path, g_strerror(errno)) << endmsg;
751 if (g_remove (tmp_path.c_str()) != 0) {
752 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
753 tmp_path, g_strerror (errno)) << endmsg;
761 save_history (snapshot_name);
763 bool was_dirty = dirty();
765 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
768 DirtyChanged (); /* EMIT SIGNAL */
771 StateSaved (snapshot_name); /* EMIT SIGNAL */
778 Session::restore_state (string snapshot_name)
780 if (load_state (snapshot_name) == 0) {
781 set_state (*state_tree->root(), Stateful::loading_state_version);
788 Session::load_state (string snapshot_name)
793 state_was_pending = false;
795 /* check for leftover pending state from a crashed capture attempt */
797 std::string xmlpath(_session_dir->root_path());
798 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
800 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
802 /* there is pending state from a crashed capture attempt */
804 boost::optional<int> r = AskAboutPendingState();
805 if (r.get_value_or (1)) {
806 state_was_pending = true;
810 if (!state_was_pending) {
811 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
814 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
815 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
816 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
817 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
822 state_tree = new XMLTree;
826 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
828 if (!state_tree->read (xmlpath)) {
829 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
835 XMLNode& root (*state_tree->root());
837 if (root.name() != X_("Session")) {
838 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
844 const XMLProperty* prop;
846 if ((prop = root.property ("version")) == 0) {
847 /* no version implies very old version of Ardour */
848 Stateful::loading_state_version = 1000;
850 if (prop->value().find ('.') != string::npos) {
851 /* old school version format */
852 if (prop->value()[0] == '2') {
853 Stateful::loading_state_version = 2000;
855 Stateful::loading_state_version = 3000;
858 Stateful::loading_state_version = atoi (prop->value());
862 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
864 std::string backup_path(_session_dir->root_path());
865 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
866 backup_path = Glib::build_filename (backup_path, backup_filename);
868 // only create a backup for a given statefile version once
870 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
872 VersionMismatch (xmlpath, backup_path);
874 if (!copy_file (xmlpath, backup_path)) {;
884 Session::load_options (const XMLNode& node)
886 LocaleGuard lg (X_("C"));
887 config.set_variables (node);
892 Session::save_default_options ()
894 return config.save_state();
904 Session::get_template()
906 /* if we don't disable rec-enable, diskstreams
907 will believe they need to store their capture
908 sources in their state node.
911 disable_record (false);
917 Session::state (bool full_state)
919 XMLNode* node = new XMLNode("Session");
923 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
924 node->add_property("version", buf);
926 /* store configuration settings */
930 node->add_property ("name", _name);
931 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
932 node->add_property ("sample-rate", buf);
934 if (session_dirs.size() > 1) {
938 vector<space_and_path>::iterator i = session_dirs.begin();
939 vector<space_and_path>::iterator next;
941 ++i; /* skip the first one */
945 while (i != session_dirs.end()) {
949 if (next != session_dirs.end()) {
950 p += G_SEARCHPATH_SEPARATOR;
959 child = node->add_child ("Path");
960 child->add_content (p);
964 /* save the ID counter */
966 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
967 node->add_property ("id-counter", buf);
969 /* save the event ID counter */
971 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
972 node->add_property ("event-counter", buf);
974 /* various options */
976 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
977 if (!midi_port_nodes.empty()) {
978 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
979 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
980 midi_port_stuff->add_child_nocopy (**n);
982 node->add_child_nocopy (*midi_port_stuff);
985 node->add_child_nocopy (config.get_variables ());
987 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
989 child = node->add_child ("Sources");
992 Glib::Threads::Mutex::Lock sl (source_lock);
994 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
996 /* Don't save information about non-file Sources, or
997 * about non-destructive file sources that are empty
998 * and unused by any regions.
1001 boost::shared_ptr<FileSource> fs;
1003 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1005 if (!fs->destructive()) {
1006 if (fs->empty() && !fs->used()) {
1011 child->add_child_nocopy (siter->second->get_state());
1016 child = node->add_child ("Regions");
1019 Glib::Threads::Mutex::Lock rl (region_lock);
1020 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1021 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1022 boost::shared_ptr<Region> r = i->second;
1023 /* only store regions not attached to playlists */
1024 if (r->playlist() == 0) {
1025 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1026 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1028 child->add_child_nocopy (r->get_state ());
1033 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1035 if (!cassocs.empty()) {
1036 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1038 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1040 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1041 i->first->id().print (buf, sizeof (buf));
1042 can->add_property (X_("copy"), buf);
1043 i->second->id().print (buf, sizeof (buf));
1044 can->add_property (X_("original"), buf);
1045 ca->add_child_nocopy (*can);
1055 node->add_child_nocopy (_locations->get_state());
1058 Locations loc (*this);
1059 // for a template, just create a new Locations, populate it
1060 // with the default start and end, and get the state for that.
1061 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1062 range->set (max_framepos, 0);
1064 XMLNode& locations_state = loc.get_state();
1066 if (ARDOUR::Profile->get_trx() && _locations) {
1067 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1068 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1069 locations_state.add_child_nocopy ((*i)->get_state ());
1073 node->add_child_nocopy (locations_state);
1076 child = node->add_child ("Bundles");
1078 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1079 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1080 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1082 child->add_child_nocopy (b->get_state());
1087 child = node->add_child ("Routes");
1089 boost::shared_ptr<RouteList> r = routes.reader ();
1091 RoutePublicOrderSorter cmp;
1092 RouteList public_order (*r);
1093 public_order.sort (cmp);
1095 /* the sort should have put control outs first */
1098 assert (_monitor_out == public_order.front());
1101 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1102 if (!(*i)->is_auditioner()) {
1104 child->add_child_nocopy ((*i)->get_state());
1106 child->add_child_nocopy ((*i)->get_template());
1112 playlists->add_state (node, full_state);
1114 child = node->add_child ("RouteGroups");
1115 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1116 child->add_child_nocopy ((*i)->get_state());
1120 XMLNode* gain_child = node->add_child ("Click");
1121 gain_child->add_child_nocopy (_click_io->state (full_state));
1122 gain_child->add_child_nocopy (_click_gain->state (full_state));
1126 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1127 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1131 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1132 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1135 node->add_child_nocopy (_speakers->get_state());
1136 node->add_child_nocopy (_tempo_map->get_state());
1137 node->add_child_nocopy (get_control_protocol_state());
1140 node->add_child_copy (*_extra_xml);
1147 Session::get_control_protocol_state ()
1149 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1150 return cpm.get_state();
1154 Session::set_state (const XMLNode& node, int version)
1158 const XMLProperty* prop;
1161 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1163 if (node.name() != X_("Session")) {
1164 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1168 if ((prop = node.property ("name")) != 0) {
1169 _name = prop->value ();
1172 if ((prop = node.property (X_("sample-rate"))) != 0) {
1174 _nominal_frame_rate = atoi (prop->value());
1176 if (_nominal_frame_rate != _current_frame_rate) {
1177 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1178 if (r.get_value_or (0)) {
1184 setup_raid_path(_session_dir->root_path());
1186 if ((prop = node.property (X_("id-counter"))) != 0) {
1188 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1189 ID::init_counter (x);
1191 /* old sessions used a timebased counter, so fake
1192 the startup ID counter based on a standard
1197 ID::init_counter (now);
1200 if ((prop = node.property (X_("event-counter"))) != 0) {
1201 Evoral::init_event_id_counter (atoi (prop->value()));
1205 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1206 _midi_ports->set_midi_port_states (child->children());
1209 IO::disable_connecting ();
1211 Stateful::save_extra_xml (node);
1213 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1214 load_options (*child);
1215 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1216 load_options (*child);
1218 error << _("Session: XML state has no options section") << endmsg;
1221 if (version >= 3000) {
1222 if ((child = find_named_node (node, "Metadata")) == 0) {
1223 warning << _("Session: XML state has no metadata section") << endmsg;
1224 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1229 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1230 _speakers->set_state (*child, version);
1233 if ((child = find_named_node (node, "Sources")) == 0) {
1234 error << _("Session: XML state has no sources section") << endmsg;
1236 } else if (load_sources (*child)) {
1240 if ((child = find_named_node (node, "TempoMap")) == 0) {
1241 error << _("Session: XML state has no Tempo Map section") << endmsg;
1243 } else if (_tempo_map->set_state (*child, version)) {
1247 if ((child = find_named_node (node, "Locations")) == 0) {
1248 error << _("Session: XML state has no locations section") << endmsg;
1250 } else if (_locations->set_state (*child, version)) {
1254 locations_changed ();
1256 if (_session_range_location) {
1257 AudioFileSource::set_header_position_offset (_session_range_location->start());
1260 if ((child = find_named_node (node, "Regions")) == 0) {
1261 error << _("Session: XML state has no Regions section") << endmsg;
1263 } else if (load_regions (*child)) {
1267 if ((child = find_named_node (node, "Playlists")) == 0) {
1268 error << _("Session: XML state has no playlists section") << endmsg;
1270 } else if (playlists->load (*this, *child)) {
1274 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1276 } else if (playlists->load_unused (*this, *child)) {
1280 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1281 if (load_compounds (*child)) {
1286 if (version >= 3000) {
1287 if ((child = find_named_node (node, "Bundles")) == 0) {
1288 warning << _("Session: XML state has no bundles section") << endmsg;
1291 /* We can't load Bundles yet as they need to be able
1292 to convert from port names to Port objects, which can't happen until
1294 _bundle_xml_node = new XMLNode (*child);
1298 if (version < 3000) {
1299 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1300 error << _("Session: XML state has no diskstreams section") << endmsg;
1302 } else if (load_diskstreams_2X (*child, version)) {
1307 if ((child = find_named_node (node, "Routes")) == 0) {
1308 error << _("Session: XML state has no routes section") << endmsg;
1310 } else if (load_routes (*child, version)) {
1314 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1315 _diskstreams_2X.clear ();
1317 if (version >= 3000) {
1319 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1320 error << _("Session: XML state has no route groups section") << endmsg;
1322 } else if (load_route_groups (*child, version)) {
1326 } else if (version < 3000) {
1328 if ((child = find_named_node (node, "EditGroups")) == 0) {
1329 error << _("Session: XML state has no edit groups section") << endmsg;
1331 } else if (load_route_groups (*child, version)) {
1335 if ((child = find_named_node (node, "MixGroups")) == 0) {
1336 error << _("Session: XML state has no mix groups section") << endmsg;
1338 } else if (load_route_groups (*child, version)) {
1343 if ((child = find_named_node (node, "Click")) == 0) {
1344 warning << _("Session: XML state has no click section") << endmsg;
1345 } else if (_click_io) {
1346 setup_click_state (&node);
1349 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1350 ControlProtocolManager::instance().set_state (*child, version);
1353 update_route_record_state ();
1355 /* here beginneth the second phase ... */
1357 StateReady (); /* EMIT SIGNAL */
1370 Session::load_routes (const XMLNode& node, int version)
1373 XMLNodeConstIterator niter;
1374 RouteList new_routes;
1376 nlist = node.children();
1380 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1382 boost::shared_ptr<Route> route;
1383 if (version < 3000) {
1384 route = XMLRouteFactory_2X (**niter, version);
1386 route = XMLRouteFactory (**niter, version);
1390 error << _("Session: cannot create Route from XML description.") << endmsg;
1394 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1396 new_routes.push_back (route);
1399 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1401 add_routes (new_routes, false, false, false);
1403 BootMessage (_("Finished adding tracks/busses"));
1408 boost::shared_ptr<Route>
1409 Session::XMLRouteFactory (const XMLNode& node, int version)
1411 boost::shared_ptr<Route> ret;
1413 if (node.name() != "Route") {
1417 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1419 DataType type = DataType::AUDIO;
1420 const XMLProperty* prop = node.property("default-type");
1423 type = DataType (prop->value());
1426 assert (type != DataType::NIL);
1430 boost::shared_ptr<Track> track;
1432 if (type == DataType::AUDIO) {
1433 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1435 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1438 if (track->init()) {
1442 if (track->set_state (node, version)) {
1446 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1447 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1452 enum Route::Flag flags = Route::Flag(0);
1453 const XMLProperty* prop = node.property("flags");
1455 flags = Route::Flag (string_2_enum (prop->value(), flags));
1458 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1460 if (r->init () == 0 && r->set_state (node, version) == 0) {
1461 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1462 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1471 boost::shared_ptr<Route>
1472 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1474 boost::shared_ptr<Route> ret;
1476 if (node.name() != "Route") {
1480 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1482 ds_prop = node.property (X_("diskstream"));
1485 DataType type = DataType::AUDIO;
1486 const XMLProperty* prop = node.property("default-type");
1489 type = DataType (prop->value());
1492 assert (type != DataType::NIL);
1496 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1497 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1501 if (i == _diskstreams_2X.end()) {
1502 error << _("Could not find diskstream for route") << endmsg;
1503 return boost::shared_ptr<Route> ();
1506 boost::shared_ptr<Track> track;
1508 if (type == DataType::AUDIO) {
1509 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1511 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1514 if (track->init()) {
1518 if (track->set_state (node, version)) {
1522 track->set_diskstream (*i);
1524 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1525 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1530 enum Route::Flag flags = Route::Flag(0);
1531 const XMLProperty* prop = node.property("flags");
1533 flags = Route::Flag (string_2_enum (prop->value(), flags));
1536 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1538 if (r->init () == 0 && r->set_state (node, version) == 0) {
1539 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1540 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1550 Session::load_regions (const XMLNode& node)
1553 XMLNodeConstIterator niter;
1554 boost::shared_ptr<Region> region;
1556 nlist = node.children();
1560 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1561 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1562 error << _("Session: cannot create Region from XML description.");
1563 const XMLProperty *name = (**niter).property("name");
1566 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1577 Session::load_compounds (const XMLNode& node)
1579 XMLNodeList calist = node.children();
1580 XMLNodeConstIterator caiter;
1581 XMLProperty *caprop;
1583 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1584 XMLNode* ca = *caiter;
1588 if ((caprop = ca->property (X_("original"))) == 0) {
1591 orig_id = caprop->value();
1593 if ((caprop = ca->property (X_("copy"))) == 0) {
1596 copy_id = caprop->value();
1598 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1599 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1601 if (!orig || !copy) {
1602 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1608 RegionFactory::add_compound_association (orig, copy);
1615 Session::load_nested_sources (const XMLNode& node)
1618 XMLNodeConstIterator niter;
1620 nlist = node.children();
1622 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1623 if ((*niter)->name() == "Source") {
1625 /* it may already exist, so don't recreate it unnecessarily
1628 XMLProperty* prop = (*niter)->property (X_("id"));
1630 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1634 ID source_id (prop->value());
1636 if (!source_by_id (source_id)) {
1639 SourceFactory::create (*this, **niter, true);
1641 catch (failed_constructor& err) {
1642 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1649 boost::shared_ptr<Region>
1650 Session::XMLRegionFactory (const XMLNode& node, bool full)
1652 const XMLProperty* type = node.property("type");
1656 const XMLNodeList& nlist = node.children();
1658 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1659 XMLNode *child = (*niter);
1660 if (child->name() == "NestedSource") {
1661 load_nested_sources (*child);
1665 if (!type || type->value() == "audio") {
1666 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1667 } else if (type->value() == "midi") {
1668 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1671 } catch (failed_constructor& err) {
1672 return boost::shared_ptr<Region> ();
1675 return boost::shared_ptr<Region> ();
1678 boost::shared_ptr<AudioRegion>
1679 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1681 const XMLProperty* prop;
1682 boost::shared_ptr<Source> source;
1683 boost::shared_ptr<AudioSource> as;
1685 SourceList master_sources;
1686 uint32_t nchans = 1;
1689 if (node.name() != X_("Region")) {
1690 return boost::shared_ptr<AudioRegion>();
1693 if ((prop = node.property (X_("channels"))) != 0) {
1694 nchans = atoi (prop->value().c_str());
1697 if ((prop = node.property ("name")) == 0) {
1698 cerr << "no name for this region\n";
1702 if ((prop = node.property (X_("source-0"))) == 0) {
1703 if ((prop = node.property ("source")) == 0) {
1704 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1705 return boost::shared_ptr<AudioRegion>();
1709 PBD::ID s_id (prop->value());
1711 if ((source = source_by_id (s_id)) == 0) {
1712 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1713 return boost::shared_ptr<AudioRegion>();
1716 as = boost::dynamic_pointer_cast<AudioSource>(source);
1718 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1719 return boost::shared_ptr<AudioRegion>();
1722 sources.push_back (as);
1724 /* pickup other channels */
1726 for (uint32_t n=1; n < nchans; ++n) {
1727 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1728 if ((prop = node.property (buf)) != 0) {
1730 PBD::ID id2 (prop->value());
1732 if ((source = source_by_id (id2)) == 0) {
1733 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1734 return boost::shared_ptr<AudioRegion>();
1737 as = boost::dynamic_pointer_cast<AudioSource>(source);
1739 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1740 return boost::shared_ptr<AudioRegion>();
1742 sources.push_back (as);
1746 for (uint32_t n = 0; n < nchans; ++n) {
1747 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1748 if ((prop = node.property (buf)) != 0) {
1750 PBD::ID id2 (prop->value());
1752 if ((source = source_by_id (id2)) == 0) {
1753 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1754 return boost::shared_ptr<AudioRegion>();
1757 as = boost::dynamic_pointer_cast<AudioSource>(source);
1759 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1760 return boost::shared_ptr<AudioRegion>();
1762 master_sources.push_back (as);
1767 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1769 /* a final detail: this is the one and only place that we know how long missing files are */
1771 if (region->whole_file()) {
1772 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1773 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1775 sfp->set_length (region->length());
1780 if (!master_sources.empty()) {
1781 if (master_sources.size() != nchans) {
1782 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1784 region->set_master_sources (master_sources);
1792 catch (failed_constructor& err) {
1793 return boost::shared_ptr<AudioRegion>();
1797 boost::shared_ptr<MidiRegion>
1798 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1800 const XMLProperty* prop;
1801 boost::shared_ptr<Source> source;
1802 boost::shared_ptr<MidiSource> ms;
1805 if (node.name() != X_("Region")) {
1806 return boost::shared_ptr<MidiRegion>();
1809 if ((prop = node.property ("name")) == 0) {
1810 cerr << "no name for this region\n";
1814 if ((prop = node.property (X_("source-0"))) == 0) {
1815 if ((prop = node.property ("source")) == 0) {
1816 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1817 return boost::shared_ptr<MidiRegion>();
1821 PBD::ID s_id (prop->value());
1823 if ((source = source_by_id (s_id)) == 0) {
1824 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1825 return boost::shared_ptr<MidiRegion>();
1828 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1830 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1831 return boost::shared_ptr<MidiRegion>();
1834 sources.push_back (ms);
1837 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1838 /* a final detail: this is the one and only place that we know how long missing files are */
1840 if (region->whole_file()) {
1841 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1842 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1844 sfp->set_length (region->length());
1852 catch (failed_constructor& err) {
1853 return boost::shared_ptr<MidiRegion>();
1858 Session::get_sources_as_xml ()
1861 XMLNode* node = new XMLNode (X_("Sources"));
1862 Glib::Threads::Mutex::Lock lm (source_lock);
1864 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1865 node->add_child_nocopy (i->second->get_state());
1872 Session::reset_write_sources (bool mark_write_complete, bool force)
1874 boost::shared_ptr<RouteList> rl = routes.reader();
1875 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1876 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1879 // block state saving
1880 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1881 tr->reset_write_sources(mark_write_complete, force);
1882 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1888 Session::load_sources (const XMLNode& node)
1891 XMLNodeConstIterator niter;
1892 boost::shared_ptr<Source> source; /* don't need this but it stops some
1893 * versions of gcc complaining about
1894 * discarded return values.
1897 nlist = node.children();
1901 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1904 if ((source = XMLSourceFactory (**niter)) == 0) {
1905 error << _("Session: cannot create Source from XML description.") << endmsg;
1908 } catch (MissingSource& err) {
1912 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1913 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1914 PROGRAM_NAME) << endmsg;
1918 if (!no_questions_about_missing_files) {
1919 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1924 switch (user_choice) {
1926 /* user added a new search location, so try again */
1931 /* user asked to quit the entire session load
1936 no_questions_about_missing_files = true;
1940 no_questions_about_missing_files = true;
1947 case DataType::AUDIO:
1948 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1951 case DataType::MIDI:
1952 /* The MIDI file is actually missing so
1953 * just create a new one in the same
1954 * location. Do not announce its
1958 if (!Glib::path_is_absolute (err.path)) {
1959 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
1961 /* this should be an unrecoverable error: we would be creating a MIDI file outside
1966 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
1967 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
1968 /* reset ID to match the missing one */
1969 source->set_id (**niter);
1970 /* Now we can announce it */
1971 SourceFactory::SourceCreated (source);
1982 boost::shared_ptr<Source>
1983 Session::XMLSourceFactory (const XMLNode& node)
1985 if (node.name() != "Source") {
1986 return boost::shared_ptr<Source>();
1990 /* note: do peak building in another thread when loading session state */
1991 return SourceFactory::create (*this, node, true);
1994 catch (failed_constructor& err) {
1995 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
1996 return boost::shared_ptr<Source>();
2001 Session::save_template (string template_name)
2003 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2007 bool absolute_path = Glib::path_is_absolute (template_name);
2009 /* directory to put the template in */
2010 std::string template_dir_path;
2012 if (!absolute_path) {
2013 std::string user_template_dir(user_template_directory());
2015 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2016 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2017 user_template_dir, g_strerror (errno)) << endmsg;
2021 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2023 template_dir_path = template_name;
2026 if (!ARDOUR::Profile->get_trx()) {
2027 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2028 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2029 template_dir_path) << endmsg;
2033 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2034 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2035 template_dir_path, g_strerror (errno)) << endmsg;
2041 std::string template_file_path;
2043 if (ARDOUR::Profile->get_trx()) {
2044 template_file_path = template_name;
2046 if (absolute_path) {
2047 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2049 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2053 SessionSaveUnderway (); /* EMIT SIGNAL */
2057 tree.set_root (&get_template());
2058 if (!tree.write (template_file_path)) {
2059 error << _("template not saved") << endmsg;
2063 if (!ARDOUR::Profile->get_trx()) {
2064 /* copy plugin state directory */
2066 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2068 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2069 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2070 template_plugin_state_path, g_strerror (errno)) << endmsg;
2073 copy_files (plugins_dir(), template_plugin_state_path);
2076 store_recent_templates (template_file_path);
2082 Session::refresh_disk_space ()
2084 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2086 Glib::Threads::Mutex::Lock lm (space_lock);
2088 /* get freespace on every FS that is part of the session path */
2090 _total_free_4k_blocks = 0;
2091 _total_free_4k_blocks_uncertain = false;
2093 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2095 struct statfs statfsbuf;
2096 statfs (i->path.c_str(), &statfsbuf);
2098 double const scale = statfsbuf.f_bsize / 4096.0;
2100 /* See if this filesystem is read-only */
2101 struct statvfs statvfsbuf;
2102 statvfs (i->path.c_str(), &statvfsbuf);
2104 /* f_bavail can be 0 if it is undefined for whatever
2105 filesystem we are looking at; Samba shares mounted
2106 via GVFS are an example of this.
2108 if (statfsbuf.f_bavail == 0) {
2109 /* block count unknown */
2111 i->blocks_unknown = true;
2112 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2113 /* read-only filesystem */
2115 i->blocks_unknown = false;
2117 /* read/write filesystem with known space */
2118 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2119 i->blocks_unknown = false;
2122 _total_free_4k_blocks += i->blocks;
2123 if (i->blocks_unknown) {
2124 _total_free_4k_blocks_uncertain = true;
2127 #elif defined PLATFORM_WINDOWS
2128 vector<string> scanned_volumes;
2129 vector<string>::iterator j;
2130 vector<space_and_path>::iterator i;
2131 DWORD nSectorsPerCluster, nBytesPerSector,
2132 nFreeClusters, nTotalClusters;
2136 _total_free_4k_blocks = 0;
2138 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2139 strncpy (disk_drive, (*i).path.c_str(), 3);
2143 volume_found = false;
2144 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2146 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2147 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2148 i->blocks = (uint32_t)(nFreeBytes / 4096);
2150 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2151 if (0 == j->compare(disk_drive)) {
2152 volume_found = true;
2157 if (!volume_found) {
2158 scanned_volumes.push_back(disk_drive);
2159 _total_free_4k_blocks += i->blocks;
2164 if (0 == _total_free_4k_blocks) {
2165 strncpy (disk_drive, path().c_str(), 3);
2168 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2170 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2171 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2172 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2179 Session::get_best_session_directory_for_new_audio ()
2181 vector<space_and_path>::iterator i;
2182 string result = _session_dir->root_path();
2184 /* handle common case without system calls */
2186 if (session_dirs.size() == 1) {
2190 /* OK, here's the algorithm we're following here:
2192 We want to select which directory to use for
2193 the next file source to be created. Ideally,
2194 we'd like to use a round-robin process so as to
2195 get maximum performance benefits from splitting
2196 the files across multiple disks.
2198 However, in situations without much diskspace, an
2199 RR approach may end up filling up a filesystem
2200 with new files while others still have space.
2201 Its therefore important to pay some attention to
2202 the freespace in the filesystem holding each
2203 directory as well. However, if we did that by
2204 itself, we'd keep creating new files in the file
2205 system with the most space until it was as full
2206 as all others, thus negating any performance
2207 benefits of this RAID-1 like approach.
2209 So, we use a user-configurable space threshold. If
2210 there are at least 2 filesystems with more than this
2211 much space available, we use RR selection between them.
2212 If not, then we pick the filesystem with the most space.
2214 This gets a good balance between the two
2218 refresh_disk_space ();
2220 int free_enough = 0;
2222 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2223 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2228 if (free_enough >= 2) {
2229 /* use RR selection process, ensuring that the one
2233 i = last_rr_session_dir;
2236 if (++i == session_dirs.end()) {
2237 i = session_dirs.begin();
2240 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2241 SessionDirectory sdir(i->path);
2242 if (sdir.create ()) {
2244 last_rr_session_dir = i;
2249 } while (i != last_rr_session_dir);
2253 /* pick FS with the most freespace (and that
2254 seems to actually work ...)
2257 vector<space_and_path> sorted;
2258 space_and_path_ascending_cmp cmp;
2260 sorted = session_dirs;
2261 sort (sorted.begin(), sorted.end(), cmp);
2263 for (i = sorted.begin(); i != sorted.end(); ++i) {
2264 SessionDirectory sdir(i->path);
2265 if (sdir.create ()) {
2267 last_rr_session_dir = i;
2277 Session::automation_dir () const
2279 return Glib::build_filename (_path, "automation");
2283 Session::analysis_dir () const
2285 return Glib::build_filename (_path, "analysis");
2289 Session::plugins_dir () const
2291 return Glib::build_filename (_path, "plugins");
2295 Session::externals_dir () const
2297 return Glib::build_filename (_path, "externals");
2301 Session::load_bundles (XMLNode const & node)
2303 XMLNodeList nlist = node.children();
2304 XMLNodeConstIterator niter;
2308 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2309 if ((*niter)->name() == "InputBundle") {
2310 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2311 } else if ((*niter)->name() == "OutputBundle") {
2312 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2314 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2323 Session::load_route_groups (const XMLNode& node, int version)
2325 XMLNodeList nlist = node.children();
2326 XMLNodeConstIterator niter;
2330 if (version >= 3000) {
2332 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2333 if ((*niter)->name() == "RouteGroup") {
2334 RouteGroup* rg = new RouteGroup (*this, "");
2335 add_route_group (rg);
2336 rg->set_state (**niter, version);
2340 } else if (version < 3000) {
2342 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2343 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2344 RouteGroup* rg = new RouteGroup (*this, "");
2345 add_route_group (rg);
2346 rg->set_state (**niter, version);
2355 state_file_filter (const string &str, void* /*arg*/)
2357 return (str.length() > strlen(statefile_suffix) &&
2358 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2362 remove_end(string state)
2364 string statename(state);
2366 string::size_type start,end;
2367 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2368 statename = statename.substr (start+1);
2371 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2372 end = statename.length();
2375 return string(statename.substr (0, end));
2379 Session::possible_states (string path)
2381 vector<string> states;
2382 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2384 transform(states.begin(), states.end(), states.begin(), remove_end);
2386 sort (states.begin(), states.end());
2392 Session::possible_states () const
2394 return possible_states(_path);
2398 Session::add_route_group (RouteGroup* g)
2400 _route_groups.push_back (g);
2401 route_group_added (g); /* EMIT SIGNAL */
2403 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2404 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2405 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2411 Session::remove_route_group (RouteGroup& rg)
2413 list<RouteGroup*>::iterator i;
2415 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2416 _route_groups.erase (i);
2419 route_group_removed (); /* EMIT SIGNAL */
2423 /** Set a new order for our route groups, without adding or removing any.
2424 * @param groups Route group list in the new order.
2427 Session::reorder_route_groups (list<RouteGroup*> groups)
2429 _route_groups = groups;
2431 route_groups_reordered (); /* EMIT SIGNAL */
2437 Session::route_group_by_name (string name)
2439 list<RouteGroup *>::iterator i;
2441 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2442 if ((*i)->name() == name) {
2450 Session::all_route_group() const
2452 return *_all_route_group;
2456 Session::add_commands (vector<Command*> const & cmds)
2458 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2464 Session::begin_reversible_command (const string& name)
2466 begin_reversible_command (g_quark_from_string (name.c_str ()));
2469 /** Begin a reversible command using a GQuark to identify it.
2470 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2471 * but there must be as many begin...()s as there are commit...()s.
2474 Session::begin_reversible_command (GQuark q)
2476 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2477 to hold all the commands that are committed. This keeps the order of
2478 commands correct in the history.
2481 if (_current_trans == 0) {
2482 /* start a new transaction */
2483 assert (_current_trans_quarks.empty ());
2484 _current_trans = new UndoTransaction();
2485 _current_trans->set_name (g_quark_to_string (q));
2488 _current_trans_quarks.push_front (q);
2492 Session::abort_reversible_command ()
2494 if (_current_trans != 0) {
2495 _current_trans->clear();
2496 delete _current_trans;
2498 _current_trans_quarks.clear();
2503 Session::commit_reversible_command (Command *cmd)
2505 assert (_current_trans);
2506 assert (!_current_trans_quarks.empty ());
2511 _current_trans->add_command (cmd);
2514 _current_trans_quarks.pop_front ();
2516 if (!_current_trans_quarks.empty ()) {
2517 /* the transaction we're committing is not the top-level one */
2521 if (_current_trans->empty()) {
2522 /* no commands were added to the transaction, so just get rid of it */
2523 delete _current_trans;
2528 gettimeofday (&now, 0);
2529 _current_trans->set_timestamp (now);
2531 _history.add (_current_trans);
2536 accept_all_audio_files (const string& path, void* /*arg*/)
2538 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2542 if (!AudioFileSource::safe_audio_file_extension (path)) {
2550 accept_all_midi_files (const string& path, void* /*arg*/)
2552 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2556 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2557 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2558 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2562 accept_all_state_files (const string& path, void* /*arg*/)
2564 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2568 std::string const statefile_ext (statefile_suffix);
2569 if (path.length() >= statefile_ext.length()) {
2570 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2577 Session::find_all_sources (string path, set<string>& result)
2582 if (!tree.read (path)) {
2586 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2591 XMLNodeConstIterator niter;
2593 nlist = node->children();
2597 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2601 if ((prop = (*niter)->property (X_("type"))) == 0) {
2605 DataType type (prop->value());
2607 if ((prop = (*niter)->property (X_("name"))) == 0) {
2611 if (Glib::path_is_absolute (prop->value())) {
2612 /* external file, ignore */
2620 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2621 result.insert (found_path);
2629 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2631 vector<string> state_files;
2633 string this_snapshot_path;
2639 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2640 ripped = ripped.substr (0, ripped.length() - 1);
2643 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2645 if (state_files.empty()) {
2650 this_snapshot_path = _path;
2651 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2652 this_snapshot_path += statefile_suffix;
2654 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2656 if (exclude_this_snapshot && *i == this_snapshot_path) {
2660 if (find_all_sources (*i, result) < 0) {
2668 struct RegionCounter {
2669 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2670 AudioSourceList::iterator iter;
2671 boost::shared_ptr<Region> region;
2674 RegionCounter() : count (0) {}
2678 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2680 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2681 return r.get_value_or (1);
2685 Session::cleanup_regions ()
2687 bool removed = false;
2688 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2690 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2692 uint32_t used = playlists->region_use_count (i->second);
2694 if (used == 0 && !i->second->automatic ()) {
2696 RegionFactory::map_remove (i->second);
2701 // re-check to remove parent references of compound regions
2702 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2703 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2706 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2707 if (0 == playlists->region_use_count (i->second)) {
2708 RegionFactory::map_remove (i->second);
2713 /* dump the history list */
2720 Session::cleanup_sources (CleanupReport& rep)
2722 // FIXME: needs adaptation to midi
2724 vector<boost::shared_ptr<Source> > dead_sources;
2727 vector<string> candidates;
2728 vector<string> unused;
2729 set<string> all_sources;
2738 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2740 /* consider deleting all unused playlists */
2742 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2747 /* sync the "all regions" property of each playlist with its current state
2750 playlists->sync_all_regions_with_regions ();
2752 /* find all un-used sources */
2757 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2759 SourceMap::iterator tmp;
2764 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2768 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2769 dead_sources.push_back (i->second);
2770 i->second->drop_references ();
2776 /* build a list of all the possible audio directories for the session */
2778 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2779 SessionDirectory sdir ((*i).path);
2780 asp += sdir.sound_path();
2782 audio_path += asp.to_string();
2785 /* build a list of all the possible midi directories for the session */
2787 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2788 SessionDirectory sdir ((*i).path);
2789 msp += sdir.midi_path();
2791 midi_path += msp.to_string();
2793 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2794 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2796 /* find all sources, but don't use this snapshot because the
2797 state file on disk still references sources we may have already
2801 find_all_sources_across_snapshots (all_sources, true);
2803 /* add our current source list
2806 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2807 boost::shared_ptr<FileSource> fs;
2808 SourceMap::iterator tmp = i;
2811 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2813 if (!fs->is_stub()) {
2815 if (playlists->source_use_count (fs) != 0) {
2816 all_sources.insert (fs->path());
2819 /* we might not remove this source from disk, because it may be used
2820 by other snapshots, but its not being used in this version
2821 so lets get rid of it now, along with any representative regions
2825 RegionFactory::remove_regions_using_source (i->second);
2828 // also remove source from all_sources
2830 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2831 spath = Glib::path_get_basename (*j);
2832 if ( spath == i->second->name () ) {
2833 all_sources.erase (j);
2844 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2849 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2851 tmppath1 = canonical_path (spath);
2852 tmppath2 = canonical_path ((*i));
2854 if (tmppath1 == tmppath2) {
2861 unused.push_back (spath);
2865 /* now try to move all unused files into the "dead" directory(ies) */
2867 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2868 struct stat statbuf;
2872 /* don't move the file across filesystems, just
2873 stick it in the `dead_dir_name' directory
2874 on whichever filesystem it was already on.
2877 if ((*x).find ("/sounds/") != string::npos) {
2879 /* old school, go up 1 level */
2881 newpath = Glib::path_get_dirname (*x); // "sounds"
2882 newpath = Glib::path_get_dirname (newpath); // "session-name"
2886 /* new school, go up 4 levels */
2888 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2889 newpath = Glib::path_get_dirname (newpath); // "session-name"
2890 newpath = Glib::path_get_dirname (newpath); // "interchange"
2891 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2894 newpath = Glib::build_filename (newpath, dead_dir_name);
2896 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2897 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2901 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2903 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2905 /* the new path already exists, try versioning */
2907 char buf[PATH_MAX+1];
2911 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2914 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2915 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2919 if (version == 999) {
2920 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2924 newpath = newpath_v;
2929 /* it doesn't exist, or we can't read it or something */
2933 stat ((*x).c_str(), &statbuf);
2935 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2936 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2937 (*x), newpath, strerror (errno))
2942 /* see if there an easy to find peakfile for this file, and remove it.
2945 string base = basename_nosuffix (*x);
2946 base += "%A"; /* this is what we add for the channel suffix of all native files,
2947 or for the first channel of embedded files. it will miss
2948 some peakfiles for other channels
2950 string peakpath = peak_path (base);
2952 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2953 if (::g_unlink (peakpath.c_str()) != 0) {
2954 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2955 peakpath, _path, strerror (errno))
2957 /* try to back out */
2958 ::rename (newpath.c_str(), _path.c_str());
2963 rep.paths.push_back (*x);
2964 rep.space += statbuf.st_size;
2967 /* dump the history list */
2971 /* save state so we don't end up a session file
2972 referring to non-existent sources.
2979 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2985 Session::cleanup_trash_sources (CleanupReport& rep)
2987 // FIXME: needs adaptation for MIDI
2989 vector<space_and_path>::iterator i;
2995 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2997 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2999 clear_directory (dead_dir, &rep.space, &rep.paths);
3006 Session::set_dirty ()
3008 /* never mark session dirty during loading */
3010 if (_state_of_the_state & Loading) {
3014 bool was_dirty = dirty();
3016 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3020 DirtyChanged(); /* EMIT SIGNAL */
3026 Session::set_clean ()
3028 bool was_dirty = dirty();
3030 _state_of_the_state = Clean;
3034 DirtyChanged(); /* EMIT SIGNAL */
3039 Session::set_deletion_in_progress ()
3041 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3045 Session::clear_deletion_in_progress ()
3047 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3051 Session::add_controllable (boost::shared_ptr<Controllable> c)
3053 /* this adds a controllable to the list managed by the Session.
3054 this is a subset of those managed by the Controllable class
3055 itself, and represents the only ones whose state will be saved
3056 as part of the session.
3059 Glib::Threads::Mutex::Lock lm (controllables_lock);
3060 controllables.insert (c);
3063 struct null_deleter { void operator()(void const *) const {} };
3066 Session::remove_controllable (Controllable* c)
3068 if (_state_of_the_state & Deletion) {
3072 Glib::Threads::Mutex::Lock lm (controllables_lock);
3074 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3076 if (x != controllables.end()) {
3077 controllables.erase (x);
3081 boost::shared_ptr<Controllable>
3082 Session::controllable_by_id (const PBD::ID& id)
3084 Glib::Threads::Mutex::Lock lm (controllables_lock);
3086 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3087 if ((*i)->id() == id) {
3092 return boost::shared_ptr<Controllable>();
3095 boost::shared_ptr<Controllable>
3096 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3098 boost::shared_ptr<Controllable> c;
3099 boost::shared_ptr<Route> r;
3101 switch (desc.top_level_type()) {
3102 case ControllableDescriptor::NamedRoute:
3104 std::string str = desc.top_level_name();
3105 if (str == "Master" || str == "master") {
3107 } else if (str == "control" || str == "listen") {
3110 r = route_by_name (desc.top_level_name());
3115 case ControllableDescriptor::RemoteControlID:
3116 r = route_by_remote_id (desc.rid());
3124 switch (desc.subtype()) {
3125 case ControllableDescriptor::Gain:
3126 c = r->gain_control ();
3129 case ControllableDescriptor::Trim:
3130 c = r->trim()->gain_control ();
3133 case ControllableDescriptor::Solo:
3134 c = r->solo_control();
3137 case ControllableDescriptor::Mute:
3138 c = r->mute_control();
3141 case ControllableDescriptor::Recenable:
3143 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3146 c = t->rec_enable_control ();
3151 case ControllableDescriptor::PanDirection:
3153 c = r->pannable()->pan_azimuth_control;
3157 case ControllableDescriptor::PanWidth:
3159 c = r->pannable()->pan_width_control;
3163 case ControllableDescriptor::PanElevation:
3165 c = r->pannable()->pan_elevation_control;
3169 case ControllableDescriptor::Balance:
3170 /* XXX simple pan control */
3173 case ControllableDescriptor::PluginParameter:
3175 uint32_t plugin = desc.target (0);
3176 uint32_t parameter_index = desc.target (1);
3178 /* revert to zero based counting */
3184 if (parameter_index > 0) {
3188 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3191 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3192 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3197 case ControllableDescriptor::SendGain:
3199 uint32_t send = desc.target (0);
3201 /* revert to zero-based counting */
3207 boost::shared_ptr<Processor> p = r->nth_send (send);
3210 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3211 boost::shared_ptr<Amp> a = s->amp();
3214 c = s->amp()->gain_control();
3221 /* relax and return a null pointer */
3229 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3232 Stateful::add_instant_xml (node, _path);
3235 if (write_to_config) {
3236 Config->add_instant_xml (node);
3241 Session::instant_xml (const string& node_name)
3243 return Stateful::instant_xml (node_name, _path);
3247 Session::save_history (string snapshot_name)
3255 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3256 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3260 if (snapshot_name.empty()) {
3261 snapshot_name = _current_snapshot_name;
3264 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3265 const string backup_filename = history_filename + backup_suffix;
3266 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3267 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3269 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3270 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3271 error << _("could not backup old history file, current history not saved") << endmsg;
3276 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3278 if (!tree.write (xml_path))
3280 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3282 if (g_remove (xml_path.c_str()) != 0) {
3283 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3284 xml_path, g_strerror (errno)) << endmsg;
3286 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3287 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3288 backup_path, g_strerror (errno)) << endmsg;
3298 Session::restore_history (string snapshot_name)
3302 if (snapshot_name.empty()) {
3303 snapshot_name = _current_snapshot_name;
3306 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3307 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3309 info << "Loading history from " << xml_path << endmsg;
3311 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3312 info << string_compose (_("%1: no history file \"%2\" for this session."),
3313 _name, xml_path) << endmsg;
3317 if (!tree.read (xml_path)) {
3318 error << string_compose (_("Could not understand session history file \"%1\""),
3319 xml_path) << endmsg;
3326 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3329 UndoTransaction* ut = new UndoTransaction ();
3332 ut->set_name(t->property("name")->value());
3333 stringstream ss(t->property("tv-sec")->value());
3335 ss.str(t->property("tv-usec")->value());
3337 ut->set_timestamp(tv);
3339 for (XMLNodeConstIterator child_it = t->children().begin();
3340 child_it != t->children().end(); child_it++)
3342 XMLNode *n = *child_it;
3345 if (n->name() == "MementoCommand" ||
3346 n->name() == "MementoUndoCommand" ||
3347 n->name() == "MementoRedoCommand") {
3349 if ((c = memento_command_factory(n))) {
3353 } else if (n->name() == "NoteDiffCommand") {
3354 PBD::ID id (n->property("midi-source")->value());
3355 boost::shared_ptr<MidiSource> midi_source =
3356 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3358 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3360 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3363 } else if (n->name() == "SysExDiffCommand") {
3365 PBD::ID id (n->property("midi-source")->value());
3366 boost::shared_ptr<MidiSource> midi_source =
3367 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3369 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3371 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3374 } else if (n->name() == "PatchChangeDiffCommand") {
3376 PBD::ID id (n->property("midi-source")->value());
3377 boost::shared_ptr<MidiSource> midi_source =
3378 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3380 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3382 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3385 } else if (n->name() == "StatefulDiffCommand") {
3386 if ((c = stateful_diff_command_factory (n))) {
3387 ut->add_command (c);
3390 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3401 Session::config_changed (std::string p, bool ours)
3407 if (p == "seamless-loop") {
3409 } else if (p == "rf-speed") {
3411 } else if (p == "auto-loop") {
3413 } else if (p == "auto-input") {
3415 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3416 /* auto-input only makes a difference if we're rolling */
3417 set_track_monitor_input_status (!config.get_auto_input());
3420 } else if (p == "punch-in") {
3424 if ((location = _locations->auto_punch_location()) != 0) {
3426 if (config.get_punch_in ()) {
3427 replace_event (SessionEvent::PunchIn, location->start());
3429 remove_event (location->start(), SessionEvent::PunchIn);
3433 } else if (p == "punch-out") {
3437 if ((location = _locations->auto_punch_location()) != 0) {
3439 if (config.get_punch_out()) {
3440 replace_event (SessionEvent::PunchOut, location->end());
3442 clear_events (SessionEvent::PunchOut);
3446 } else if (p == "edit-mode") {
3448 Glib::Threads::Mutex::Lock lm (playlists->lock);
3450 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3451 (*i)->set_edit_mode (Config->get_edit_mode ());
3454 } else if (p == "use-video-sync") {
3456 waiting_for_sync_offset = config.get_use_video_sync();
3458 } else if (p == "mmc-control") {
3460 //poke_midi_thread ();
3462 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3464 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3466 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3468 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3470 } else if (p == "midi-control") {
3472 //poke_midi_thread ();
3474 } else if (p == "raid-path") {
3476 setup_raid_path (config.get_raid_path());
3478 } else if (p == "timecode-format") {
3482 } else if (p == "video-pullup") {
3486 } else if (p == "seamless-loop") {
3488 if (play_loop && transport_rolling()) {
3489 // to reset diskstreams etc
3490 request_play_loop (true);
3493 } else if (p == "rf-speed") {
3495 cumulative_rf_motion = 0;
3498 } else if (p == "click-sound") {
3500 setup_click_sounds (1);
3502 } else if (p == "click-emphasis-sound") {
3504 setup_click_sounds (-1);
3506 } else if (p == "clicking") {
3508 if (Config->get_clicking()) {
3509 if (_click_io && click_data) { // don't require emphasis data
3516 } else if (p == "click-gain") {
3519 _click_gain->set_gain (Config->get_click_gain(), this);
3522 } else if (p == "send-mtc") {
3524 if (Config->get_send_mtc ()) {
3525 /* mark us ready to send */
3526 next_quarter_frame_to_send = 0;
3529 } else if (p == "send-mmc") {
3531 _mmc->enable_send (Config->get_send_mmc ());
3533 } else if (p == "midi-feedback") {
3535 session_midi_feedback = Config->get_midi_feedback();
3537 } else if (p == "jack-time-master") {
3539 engine().reset_timebase ();
3541 } else if (p == "native-file-header-format") {
3543 if (!first_file_header_format_reset) {
3544 reset_native_file_format ();
3547 first_file_header_format_reset = false;
3549 } else if (p == "native-file-data-format") {
3551 if (!first_file_data_format_reset) {
3552 reset_native_file_format ();
3555 first_file_data_format_reset = false;
3557 } else if (p == "external-sync") {
3558 if (!config.get_external_sync()) {
3559 drop_sync_source ();
3561 switch_to_sync_source (Config->get_sync_source());
3563 } else if (p == "denormal-model") {
3565 } else if (p == "history-depth") {
3566 set_history_depth (Config->get_history_depth());
3567 } else if (p == "remote-model") {
3568 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3571 } else if (p == "initial-program-change") {
3573 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3576 buf[0] = MIDI::program; // channel zero by default
3577 buf[1] = (Config->get_initial_program_change() & 0x7f);
3579 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3581 } else if (p == "solo-mute-override") {
3582 // catch_up_on_solo_mute_override ();
3583 } else if (p == "listen-position" || p == "pfl-position") {
3584 listen_position_changed ();
3585 } else if (p == "solo-control-is-listen-control") {
3586 solo_control_mode_changed ();
3587 } else if (p == "solo-mute-gain") {
3588 _solo_cut_control->Changed();
3589 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3590 last_timecode_valid = false;
3591 } else if (p == "playback-buffer-seconds") {
3592 AudioSource::allocate_working_buffers (frame_rate());
3593 } else if (p == "ltc-source-port") {
3594 reconnect_ltc_input ();
3595 } else if (p == "ltc-sink-port") {
3596 reconnect_ltc_output ();
3597 } else if (p == "timecode-generator-offset") {
3598 ltc_tx_parse_offset();
3605 Session::set_history_depth (uint32_t d)
3607 _history.set_depth (d);
3611 Session::load_diskstreams_2X (XMLNode const & node, int)
3614 XMLNodeConstIterator citer;
3616 clist = node.children();
3618 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3621 /* diskstreams added automatically by DiskstreamCreated handler */
3622 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3623 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3624 _diskstreams_2X.push_back (dsp);
3626 error << _("Session: unknown diskstream type in XML") << endmsg;
3630 catch (failed_constructor& err) {
3631 error << _("Session: could not load diskstream via XML state") << endmsg;
3639 /** Connect things to the MMC object */
3641 Session::setup_midi_machine_control ()
3643 _mmc = new MIDI::MachineControl;
3644 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3646 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3647 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3648 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3649 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3650 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3651 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3652 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3653 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3654 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3655 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3656 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3657 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3658 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3660 /* also handle MIDI SPP because its so common */
3662 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3663 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3664 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3667 boost::shared_ptr<Controllable>
3668 Session::solo_cut_control() const
3670 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3671 controls in Ardour that currently get presented to the user in the GUI that require
3672 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3674 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3675 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3679 return _solo_cut_control;
3683 Session::rename (const std::string& new_name)
3685 string legal_name = legalize_for_path (new_name);
3691 string const old_sources_root = _session_dir->sources_root();
3693 if (!_writable || (_state_of_the_state & CannotSave)) {
3694 error << _("Cannot rename read-only session.") << endmsg;
3695 return 0; // don't show "messed up" warning
3697 if (record_status() == Recording) {
3698 error << _("Cannot rename session while recording") << endmsg;
3699 return 0; // don't show "messed up" warning
3702 StateProtector stp (this);
3707 * interchange subdirectory
3711 * Backup files are left unchanged and not renamed.
3714 /* Windows requires that we close all files before attempting the
3715 * rename. This works on other platforms, but isn't necessary there.
3716 * Leave it in place for all platforms though, since it may help
3717 * catch issues that could arise if the way Source files work ever
3718 * change (since most developers are not using Windows).
3721 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3722 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3728 /* pass one: not 100% safe check that the new directory names don't
3732 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3736 /* this is a stupid hack because Glib::path_get_dirname() is
3737 * lexical-only, and so passing it /a/b/c/ gives a different
3738 * result than passing it /a/b/c ...
3741 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3742 oldstr = oldstr.substr (0, oldstr.length() - 1);
3745 string base = Glib::path_get_dirname (oldstr);
3747 newstr = Glib::build_filename (base, legal_name);
3749 cerr << "Looking for " << newstr << endl;
3751 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3752 cerr << " exists\n";
3761 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3767 /* this is a stupid hack because Glib::path_get_dirname() is
3768 * lexical-only, and so passing it /a/b/c/ gives a different
3769 * result than passing it /a/b/c ...
3772 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3773 oldstr = oldstr.substr (0, oldstr.length() - 1);
3776 string base = Glib::path_get_dirname (oldstr);
3777 newstr = Glib::build_filename (base, legal_name);
3779 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3781 cerr << "Rename " << oldstr << " => " << newstr << endl;
3782 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3783 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3784 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3788 /* Reset path in "session dirs" */
3793 /* reset primary SessionDirectory object */
3796 (*_session_dir) = newstr;
3801 /* now rename directory below session_dir/interchange */
3803 string old_interchange_dir;
3804 string new_interchange_dir;
3806 /* use newstr here because we renamed the path
3807 * (folder/directory) that used to be oldstr to newstr above
3810 v.push_back (newstr);
3811 v.push_back (interchange_dir_name);
3812 v.push_back (Glib::path_get_basename (oldstr));
3814 old_interchange_dir = Glib::build_filename (v);
3817 v.push_back (newstr);
3818 v.push_back (interchange_dir_name);
3819 v.push_back (legal_name);
3821 new_interchange_dir = Glib::build_filename (v);
3823 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3825 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3826 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3827 old_interchange_dir, new_interchange_dir,
3830 error << string_compose (_("renaming %s as %2 failed (%3)"),
3831 old_interchange_dir, new_interchange_dir,
3840 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3841 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3843 cerr << "Rename " << oldstr << " => " << newstr << endl;
3845 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3846 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3847 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3853 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3855 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3856 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3858 cerr << "Rename " << oldstr << " => " << newstr << endl;
3860 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3861 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3862 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3867 /* remove old name from recent sessions */
3868 remove_recent_sessions (_path);
3871 /* update file source paths */
3873 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3874 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3876 string p = fs->path ();
3877 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3879 SourceFactory::setup_peakfile(i->second, true);
3883 _current_snapshot_name = new_name;
3888 /* save state again to get everything just right */
3890 save_state (_current_snapshot_name);
3892 /* add to recent sessions */
3894 store_recent_sessions (new_name, _path);
3900 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3902 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3906 if (!tree.read (xmlpath)) {
3914 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3917 bool found_sr = false;
3918 bool found_data_format = false;
3920 if (get_session_info_from_path (tree, xmlpath)) {
3926 const XMLProperty* prop;
3927 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3928 sample_rate = atoi (prop->value());
3932 const XMLNodeList& children (tree.root()->children());
3933 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3934 const XMLNode* child = *c;
3935 if (child->name() == "Config") {
3936 const XMLNodeList& options (child->children());
3937 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3938 const XMLNode* option = *oc;
3939 const XMLProperty* name = option->property("name");
3945 if (name->value() == "native-file-data-format") {
3946 const XMLProperty* value = option->property ("value");
3948 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3950 found_data_format = true;
3956 if (found_data_format) {
3961 return !(found_sr && found_data_format); // zero if they are both found
3964 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
3965 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
3968 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
3972 SourcePathMap source_path_map;
3974 boost::shared_ptr<AudioFileSource> afs;
3979 Glib::Threads::Mutex::Lock lm (source_lock);
3981 cerr << " total sources = " << sources.size();
3983 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3984 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3990 if (fs->within_session()) {
3994 if (source_path_map.find (fs->path()) != source_path_map.end()) {
3995 source_path_map[fs->path()].push_back (fs);
3997 SeveralFileSources v;
3999 source_path_map.insert (make_pair (fs->path(), v));
4005 cerr << " fsources = " << total << endl;
4007 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4009 /* tell caller where we are */
4011 string old_path = i->first;
4013 callback (n, total, old_path);
4015 cerr << old_path << endl;
4019 switch (i->second.front()->type()) {
4020 case DataType::AUDIO:
4021 new_path = new_audio_source_path_for_embedded (old_path);
4024 case DataType::MIDI:
4025 /* XXX not implemented yet */
4029 if (new_path.empty()) {
4033 cerr << "Move " << old_path << " => " << new_path << endl;
4035 if (!copy_file (old_path, new_path)) {
4036 cerr << "failed !\n";
4040 /* make sure we stop looking in the external
4041 dir/folder. Remember, this is an all-or-nothing
4042 operations, it doesn't merge just some files.
4044 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4046 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4047 (*f)->set_path (new_path);
4052 save_state ("", false, false);
4058 bool accept_all_files (string const &, void *)
4064 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4066 /* 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.
4071 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4073 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4075 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4077 v.push_back (new_session_folder); /* full path */
4078 v.push_back (interchange_dir_name);
4079 v.push_back (new_session_path); /* just one directory/folder */
4080 v.push_back (typedir);
4081 v.push_back (Glib::path_get_basename (old_path));
4083 return Glib::build_filename (v);
4087 Session::save_as (SaveAs& saveas)
4089 vector<string> files;
4090 string current_folder = Glib::path_get_dirname (_path);
4091 string new_folder = legalize_for_path (saveas.new_name);
4092 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4093 int64_t total_bytes = 0;
4097 int32_t internal_file_cnt = 0;
4099 vector<string> do_not_copy_extensions;
4100 do_not_copy_extensions.push_back (statefile_suffix);
4101 do_not_copy_extensions.push_back (pending_suffix);
4102 do_not_copy_extensions.push_back (backup_suffix);
4103 do_not_copy_extensions.push_back (temp_suffix);
4104 do_not_copy_extensions.push_back (history_suffix);
4106 /* get total size */
4108 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4110 /* need to clear this because
4111 * find_files_matching_filter() is cumulative
4116 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4118 all += files.size();
4120 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4122 g_stat ((*i).c_str(), &gsb);
4123 total_bytes += gsb.st_size;
4127 /* save old values so we can switch back if we are not switching to the new session */
4129 string old_path = _path;
4130 string old_name = _name;
4131 string old_snapshot = _current_snapshot_name;
4132 string old_sd = _session_dir->root_path();
4133 vector<string> old_search_path[DataType::num_types];
4134 string old_config_search_path[DataType::num_types];
4136 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4137 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4138 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4139 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4141 /* switch session directory */
4143 (*_session_dir) = to_dir;
4145 /* create new tree */
4147 if (!_session_dir->create()) {
4148 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4153 /* copy all relevant files. Find each location in session_dirs,
4154 * and copy files from there to target.
4157 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4159 /* need to clear this because
4160 * find_files_matching_filter() is cumulative
4165 const size_t prefix_len = (*sd).path.size();
4167 /* Work just on the files within this session dir */
4169 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4171 /* add dir separator to protect against collisions with
4172 * track names (e.g. track named "audiofiles" or
4176 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4177 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4178 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4180 /* copy all the files. Handling is different for media files
4181 than others because of the *silly* subtree we have below the interchange
4182 folder. That really was a bad idea, but I'm not fixing it as part of
4183 implementing ::save_as().
4186 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4188 std::string from = *i;
4191 string filename = Glib::path_get_basename (from);
4192 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4193 if (filename == ".DS_STORE") {
4198 if (from.find (audiofile_dir_string) != string::npos) {
4200 /* audio file: only copy if asked */
4202 if (saveas.include_media && saveas.copy_media) {
4204 string to = make_new_media_path (*i, to_dir, new_folder);
4206 info << "media file copying from " << from << " to " << to << endmsg;
4208 if (!copy_file (from, to)) {
4209 throw Glib::FileError (Glib::FileError::IO_ERROR,
4210 string_compose(_("\ncopying \"%1\" failed !"), from));
4214 /* we found media files inside the session folder */
4216 internal_file_cnt++;
4218 } else if (from.find (midifile_dir_string) != string::npos) {
4220 /* midi file: always copy unless
4221 * creating an empty new session
4224 if (saveas.include_media) {
4226 string to = make_new_media_path (*i, to_dir, new_folder);
4228 info << "media file copying from " << from << " to " << to << endmsg;
4230 if (!copy_file (from, to)) {
4231 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4235 /* we found media files inside the session folder */
4237 internal_file_cnt++;
4239 } else if (from.find (analysis_dir_string) != string::npos) {
4241 /* make sure analysis dir exists in
4242 * new session folder, but we're not
4243 * copying analysis files here, see
4247 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4252 /* normal non-media file. Don't copy state, history, etc.
4255 bool do_copy = true;
4257 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4258 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4259 /* end of filename matches extension, do not copy file */
4265 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4266 /* don't copy peakfiles if
4267 * we're not copying media
4273 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4275 info << "attempting to make directory/folder " << to << endmsg;
4277 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4278 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4281 info << "attempting to copy " << from << " to " << to << endmsg;
4283 if (!copy_file (from, to)) {
4284 throw Glib::FileError (Glib::FileError::IO_ERROR,
4285 string_compose(_("\ncopying \"%1\" failed !"), from));
4290 /* measure file size even if we're not going to copy so that our Progress
4291 signals are correct, since we included these do-not-copy files
4292 in the computation of the total size and file count.
4296 g_stat (from.c_str(), &gsb);
4297 copied += gsb.st_size;
4300 double fraction = (double) copied / total_bytes;
4302 bool keep_going = true;
4304 if (saveas.copy_media) {
4306 /* no need or expectation of this if
4307 * media is not being copied, because
4308 * it will be fast(ish).
4311 /* tell someone "X percent, file M of N"; M is one-based */
4313 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4321 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4327 /* copy optional folders, if any */
4329 string old = plugins_dir ();
4330 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4331 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4332 copy_files (old, newdir);
4335 old = externals_dir ();
4336 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4337 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4338 copy_files (old, newdir);
4341 old = automation_dir ();
4342 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4343 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4344 copy_files (old, newdir);
4347 if (saveas.include_media) {
4349 if (saveas.copy_media) {
4350 #ifndef PLATFORM_WINDOWS
4351 /* There are problems with analysis files on
4352 * Windows, because they used a colon in their
4353 * names as late as 4.0. Colons are not legal
4354 * under Windows even if NTFS allows them.
4356 * This is a tricky problem to solve so for
4357 * just don't copy these files. They will be
4358 * regenerated as-needed anyway, subject to the
4359 * existing issue that the filenames will be
4360 * rejected by Windows, which is a separate
4361 * problem (though related).
4364 /* only needed if we are copying media, since the
4365 * analysis data refers to media data
4368 old = analysis_dir ();
4369 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4370 string newdir = Glib::build_filename (to_dir, "analysis");
4371 copy_files (old, newdir);
4373 #endif /* PLATFORM_WINDOWS */
4379 _current_snapshot_name = saveas.new_name;
4380 _name = saveas.new_name;
4382 if (saveas.include_media && !saveas.copy_media) {
4384 /* reset search paths of the new session (which we're pretending to be right now) to
4385 include the original session search path, so we can still find all audio.
4388 if (internal_file_cnt) {
4389 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4390 ensure_search_path_includes (*s, DataType::AUDIO);
4393 /* we do not do this for MIDI because we copy
4394 all MIDI files if saveas.include_media is
4400 bool was_dirty = dirty ();
4402 save_state ("", false, false, !saveas.include_media);
4403 save_default_options ();
4405 if (saveas.copy_media && saveas.copy_external) {
4406 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4407 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4411 saveas.final_session_folder_name = _path;
4413 store_recent_sessions (_name, _path);
4415 if (!saveas.switch_to) {
4417 /* switch back to the way things were */
4421 _current_snapshot_name = old_snapshot;
4423 (*_session_dir) = old_sd;
4429 if (internal_file_cnt) {
4430 /* reset these to their original values */
4431 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4432 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4437 /* prune session dirs, and update disk space statistics
4442 session_dirs.clear ();
4443 session_dirs.push_back (sp);
4444 refresh_disk_space ();
4446 /* ensure that all existing tracks reset their current capture source paths
4448 reset_write_sources (true, true);
4450 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4451 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4454 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4455 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4461 if (fs->within_session()) {
4462 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4463 fs->set_path (newpath);
4468 } catch (Glib::FileError& e) {
4470 saveas.failure_message = e.what();
4472 /* recursively remove all the directories */
4474 remove_directory (to_dir);
4482 saveas.failure_message = _("unknown reason");
4484 /* recursively remove all the directories */
4486 remove_directory (to_dir);