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);
145 if (Profile->get_trx() ) {
146 // Waves TracksLive has a usecase of session replacement with a new one.
147 // We should check session state file (<session_name>.ardour) existance
148 // to determine if the session is new or not
150 string full_session_name = Glib::build_filename( fullpath, _name );
151 full_session_name += statefile_suffix;
153 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
155 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
158 /* finish initialization that can't be done in a normal C++ constructor
162 timerclear (&last_mmc_step);
163 g_atomic_int_set (&processing_prohibited, 0);
164 g_atomic_int_set (&_record_status, Disabled);
165 g_atomic_int_set (&_playback_load, 100);
166 g_atomic_int_set (&_capture_load, 100);
168 _all_route_group->set_active (true, this);
169 interpolation.add_channel_to (0, 0);
171 if (config.get_use_video_sync()) {
172 waiting_for_sync_offset = true;
174 waiting_for_sync_offset = false;
177 last_rr_session_dir = session_dirs.begin();
179 set_history_depth (Config->get_history_depth());
181 /* default: assume simple stereo speaker configuration */
183 _speakers->setup_default_speakers (2);
185 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
186 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
187 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
188 add_controllable (_solo_cut_control);
190 /* These are all static "per-class" signals */
192 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
193 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
194 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
195 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
196 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
198 /* stop IO objects from doing stuff until we're ready for them */
200 Delivery::disable_panners ();
201 IO::disable_connecting ();
203 AudioFileSource::set_peak_dir (_session_dir->peak_path());
207 Session::post_engine_init ()
209 BootMessage (_("Set block size and sample rate"));
211 set_block_size (_engine.samples_per_cycle());
212 set_frame_rate (_engine.sample_rate());
214 BootMessage (_("Using configuration"));
216 _midi_ports = new MidiPortManager;
218 MIDISceneChanger* msc;
220 _scene_changer = msc = new MIDISceneChanger (*this);
221 msc->set_input_port (scene_input_port());
222 msc->set_output_port (scene_out());
224 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
225 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
227 setup_midi_machine_control ();
229 if (_butler->start_thread()) {
233 if (start_midi_thread ()) {
237 setup_click_sounds (0);
238 setup_midi_control ();
240 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
241 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
244 /* tempo map requires sample rate knowledge */
247 _tempo_map = new TempoMap (_current_frame_rate);
248 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
250 /* MidiClock requires a tempo map */
252 midi_clock = new MidiClockTicker ();
253 midi_clock->set_session (this);
255 /* crossfades require sample rate knowledge */
257 SndFileSource::setup_standard_crossfades (*this, frame_rate());
258 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
260 AudioDiskstream::allocate_working_buffers();
261 refresh_disk_space ();
263 /* we're finally ready to call set_state() ... all objects have
264 * been created, the engine is running.
268 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
272 // set_state() will call setup_raid_path(), but if it's a new session we need
273 // to call setup_raid_path() here.
274 setup_raid_path (_path);
279 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
280 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
282 Config->map_parameters (ff);
283 config.map_parameters (ft);
284 _butler->map_parameters ();
286 /* Reset all panners */
288 Delivery::reset_panners ();
290 /* this will cause the CPM to instantiate any protocols that are in use
291 * (or mandatory), which will pass it this Session, and then call
292 * set_state() on each instantiated protocol to match stored state.
295 ControlProtocolManager::instance().set_session (this);
297 /* This must be done after the ControlProtocolManager set_session above,
298 as it will set states for ports which the ControlProtocolManager creates.
301 // XXX set state of MIDI::Port's
302 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
304 /* And this must be done after the MIDI::Manager::set_port_states as
305 * it will try to make connections whose details are loaded by set_port_states.
310 /* Let control protocols know that we are now all connected, so they
311 * could start talking to surfaces if they want to.
314 ControlProtocolManager::instance().midi_connectivity_established ();
316 if (_is_new && !no_auto_connect()) {
317 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
318 auto_connect_master_bus ();
321 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
323 /* update latencies */
325 initialize_latencies ();
327 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
328 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
329 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
331 } catch (AudioEngine::PortRegistrationFailure& err) {
332 /* handle this one in a different way than all others, so that its clear what happened */
333 error << err.what() << endmsg;
339 BootMessage (_("Reset Remote Controls"));
341 // send_full_time_code (0);
342 _engine.transport_locate (0);
344 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
345 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
347 MIDI::Name::MidiPatchManager::instance().set_session (this);
350 /* initial program change will be delivered later; see ::config_changed() */
352 _state_of_the_state = Clean;
354 Port::set_connecting_blocked (false);
356 DirtyChanged (); /* EMIT SIGNAL */
360 } else if (state_was_pending) {
362 remove_pending_capture_state ();
363 state_was_pending = false;
366 /* Now, finally, we can fill the playback buffers */
368 BootMessage (_("Filling playback buffers"));
370 boost::shared_ptr<RouteList> rl = routes.reader();
371 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
372 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
373 if (trk && !trk->hidden()) {
374 trk->seek (_transport_frame, true);
382 Session::session_loaded ()
386 _state_of_the_state = Clean;
388 DirtyChanged (); /* EMIT SIGNAL */
392 } else if (state_was_pending) {
394 remove_pending_capture_state ();
395 state_was_pending = false;
398 /* Now, finally, we can fill the playback buffers */
400 BootMessage (_("Filling playback buffers"));
401 force_locate (_transport_frame, false);
405 Session::raid_path () const
407 Searchpath raid_search_path;
409 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
410 raid_search_path += (*i).path;
413 return raid_search_path.to_string ();
417 Session::setup_raid_path (string path)
426 session_dirs.clear ();
428 Searchpath search_path(path);
429 Searchpath sound_search_path;
430 Searchpath midi_search_path;
432 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
434 sp.blocks = 0; // not needed
435 session_dirs.push_back (sp);
437 SessionDirectory sdir(sp.path);
439 sound_search_path += sdir.sound_path ();
440 midi_search_path += sdir.midi_path ();
443 // reset the round-robin soundfile path thingie
444 last_rr_session_dir = session_dirs.begin();
448 Session::path_is_within_session (const std::string& path)
450 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
451 if (PBD::path_is_within (i->path, path)) {
459 Session::ensure_subdirs ()
463 dir = session_directory().peak_path();
465 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
466 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
470 dir = session_directory().sound_path();
472 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
473 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
477 dir = session_directory().midi_path();
479 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
480 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
484 dir = session_directory().dead_path();
486 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
487 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
491 dir = session_directory().export_path();
493 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
494 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
498 dir = analysis_dir ();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
505 dir = plugins_dir ();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
512 dir = externals_dir ();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
522 /** @param session_template directory containing session template, or empty.
523 * Caller must not hold process lock.
526 Session::create (const string& session_template, BusProfile* bus_profile)
528 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
529 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
533 if (ensure_subdirs ()) {
537 _writable = exists_and_writable (_path);
539 if (!session_template.empty()) {
540 std::string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
542 ifstream in(in_path.c_str());
545 /* no need to call legalize_for_path() since the string
546 * in session_template is already a legal path name
548 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
550 ofstream out(out_path.c_str());
556 if (!ARDOUR::Profile->get_trx()) {
557 /* Copy plugin state files from template to new session */
558 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
559 copy_recurse (template_plugins, plugins_dir ());
565 error << string_compose (_("Could not open %1 for writing session template"), out_path)
571 error << string_compose (_("Could not open session template %1 for reading"), in_path)
578 if (Profile->get_trx()) {
580 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
581 Remember that this is a brand new session. Sessions
582 loaded from saved state will get this range from the saved state.
585 set_session_range_location (0, 0);
587 /* Initial loop location, from absolute zero, length 10 seconds */
589 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
590 _locations->add (loc, true);
591 set_auto_loop_location (loc);
594 _state_of_the_state = Clean;
596 /* set up Master Out and Control Out if necessary */
601 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
603 // Waves Tracks: always create master bus for Tracks
604 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
605 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
609 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
610 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
613 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
614 r->input()->ensure_io (count, false, this);
615 r->output()->ensure_io (count, false, this);
621 /* prohibit auto-connect to master, because there isn't one */
622 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
626 add_routes (rl, false, false, false);
629 // Waves Tracks: Skip this. Always use autoconnection for Tracks
630 if (!ARDOUR::Profile->get_trx()) {
632 /* this allows the user to override settings with an environment variable.
635 if (no_auto_connect()) {
636 bus_profile->input_ac = AutoConnectOption (0);
637 bus_profile->output_ac = AutoConnectOption (0);
640 Config->set_input_auto_connect (bus_profile->input_ac);
641 Config->set_output_auto_connect (bus_profile->output_ac);
645 if (Config->get_use_monitor_bus() && bus_profile) {
646 add_monitor_section ();
653 Session::maybe_write_autosave()
655 if (dirty() && record_status() != Recording) {
656 save_state("", true);
661 Session::remove_pending_capture_state ()
663 std::string pending_state_file_path(_session_dir->root_path());
665 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
667 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
669 if (g_remove (pending_state_file_path.c_str()) != 0) {
670 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
671 pending_state_file_path, g_strerror (errno)) << endmsg;
675 /** Rename a state file.
676 * @param old_name Old snapshot name.
677 * @param new_name New snapshot name.
680 Session::rename_state (string old_name, string new_name)
682 if (old_name == _current_snapshot_name || old_name == _name) {
683 /* refuse to rename the current snapshot or the "main" one */
687 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
688 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
690 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
691 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
693 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
694 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
695 old_name, new_name, g_strerror(errno)) << endmsg;
699 /** Remove a state file.
700 * @param snapshot_name Snapshot name.
703 Session::remove_state (string snapshot_name)
705 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
706 // refuse to remove the current snapshot or the "main" one
710 std::string xml_path(_session_dir->root_path());
712 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
714 if (!create_backup_file (xml_path)) {
715 // don't remove it if a backup can't be made
716 // create_backup_file will log the error.
721 if (g_remove (xml_path.c_str()) != 0) {
722 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
723 xml_path, g_strerror (errno)) << endmsg;
727 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
729 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
732 std::string xml_path(_session_dir->root_path());
734 /* prevent concurrent saves from different threads */
736 Glib::Threads::Mutex::Lock lm (save_state_lock);
738 if (!_writable || (_state_of_the_state & CannotSave)) {
742 if (g_atomic_int_get(&_suspend_save)) {
746 _save_queued = false;
748 if (!_engine.connected ()) {
749 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
755 /* tell sources we're saving first, in case they write out to a new file
756 * which should be saved with the state rather than the old one */
757 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
759 i->second->session_saved();
760 } catch (Evoral::SMF::FileError& e) {
761 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
765 SessionSaveUnderway (); /* EMIT SIGNAL */
768 tree.set_root (&get_template());
770 tree.set_root (&get_state());
773 if (snapshot_name.empty()) {
774 snapshot_name = _current_snapshot_name;
775 } else if (switch_to_snapshot) {
776 _current_snapshot_name = snapshot_name;
781 /* proper save: use statefile_suffix (.ardour in English) */
783 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
785 /* make a backup copy of the old file */
787 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
788 // create_backup_file will log the error
794 /* pending save: use pending_suffix (.pending in English) */
795 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
798 std::string tmp_path(_session_dir->root_path());
799 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
801 cerr << "actually writing state to " << tmp_path << endl;
803 if (!tree.write (tmp_path)) {
804 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
805 if (g_remove (tmp_path.c_str()) != 0) {
806 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
807 tmp_path, g_strerror (errno)) << endmsg;
813 cerr << "renaming state to " << xml_path << endl;
815 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
816 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
817 tmp_path, xml_path, g_strerror(errno)) << endmsg;
818 if (g_remove (tmp_path.c_str()) != 0) {
819 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
820 tmp_path, g_strerror (errno)) << endmsg;
828 save_history (snapshot_name);
830 bool was_dirty = dirty();
832 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
835 DirtyChanged (); /* EMIT SIGNAL */
838 StateSaved (snapshot_name); /* EMIT SIGNAL */
845 Session::restore_state (string snapshot_name)
847 if (load_state (snapshot_name) == 0) {
848 set_state (*state_tree->root(), Stateful::loading_state_version);
855 Session::load_state (string snapshot_name)
860 state_was_pending = false;
862 /* check for leftover pending state from a crashed capture attempt */
864 std::string xmlpath(_session_dir->root_path());
865 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
867 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
869 /* there is pending state from a crashed capture attempt */
871 boost::optional<int> r = AskAboutPendingState();
872 if (r.get_value_or (1)) {
873 state_was_pending = true;
877 if (!state_was_pending) {
878 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
881 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
882 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
883 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
884 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
889 state_tree = new XMLTree;
893 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
895 if (!state_tree->read (xmlpath)) {
896 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
902 XMLNode& root (*state_tree->root());
904 if (root.name() != X_("Session")) {
905 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
911 const XMLProperty* prop;
913 if ((prop = root.property ("version")) == 0) {
914 /* no version implies very old version of Ardour */
915 Stateful::loading_state_version = 1000;
917 if (prop->value().find ('.') != string::npos) {
918 /* old school version format */
919 if (prop->value()[0] == '2') {
920 Stateful::loading_state_version = 2000;
922 Stateful::loading_state_version = 3000;
925 Stateful::loading_state_version = atoi (prop->value());
929 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
931 std::string backup_path(_session_dir->root_path());
932 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
933 backup_path = Glib::build_filename (backup_path, backup_filename);
935 // only create a backup for a given statefile version once
937 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
939 VersionMismatch (xmlpath, backup_path);
941 if (!copy_file (xmlpath, backup_path)) {;
951 Session::load_options (const XMLNode& node)
953 LocaleGuard lg (X_("C"));
954 config.set_variables (node);
959 Session::save_default_options ()
961 return config.save_state();
971 Session::get_template()
973 /* if we don't disable rec-enable, diskstreams
974 will believe they need to store their capture
975 sources in their state node.
978 disable_record (false);
984 Session::state (bool full_state)
986 XMLNode* node = new XMLNode("Session");
990 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
991 node->add_property("version", buf);
993 /* store configuration settings */
997 node->add_property ("name", _name);
998 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
999 node->add_property ("sample-rate", buf);
1001 if (session_dirs.size() > 1) {
1005 vector<space_and_path>::iterator i = session_dirs.begin();
1006 vector<space_and_path>::iterator next;
1008 ++i; /* skip the first one */
1012 while (i != session_dirs.end()) {
1016 if (next != session_dirs.end()) {
1017 p += G_SEARCHPATH_SEPARATOR;
1026 child = node->add_child ("Path");
1027 child->add_content (p);
1031 /* save the ID counter */
1033 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1034 node->add_property ("id-counter", buf);
1036 /* save the event ID counter */
1038 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1039 node->add_property ("event-counter", buf);
1041 /* various options */
1043 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1044 if (!midi_port_nodes.empty()) {
1045 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1046 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1047 midi_port_stuff->add_child_nocopy (**n);
1049 node->add_child_nocopy (*midi_port_stuff);
1052 node->add_child_nocopy (config.get_variables ());
1054 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1056 child = node->add_child ("Sources");
1059 Glib::Threads::Mutex::Lock sl (source_lock);
1061 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1063 /* Don't save information about non-file Sources, or
1064 * about non-destructive file sources that are empty
1065 * and unused by any regions.
1068 boost::shared_ptr<FileSource> fs;
1070 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1072 if (!fs->destructive()) {
1073 if (fs->empty() && !fs->used()) {
1078 child->add_child_nocopy (siter->second->get_state());
1083 child = node->add_child ("Regions");
1086 Glib::Threads::Mutex::Lock rl (region_lock);
1087 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1088 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1089 boost::shared_ptr<Region> r = i->second;
1090 /* only store regions not attached to playlists */
1091 if (r->playlist() == 0) {
1092 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1093 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1095 child->add_child_nocopy (r->get_state ());
1100 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1102 if (!cassocs.empty()) {
1103 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1105 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1107 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1108 i->first->id().print (buf, sizeof (buf));
1109 can->add_property (X_("copy"), buf);
1110 i->second->id().print (buf, sizeof (buf));
1111 can->add_property (X_("original"), buf);
1112 ca->add_child_nocopy (*can);
1122 node->add_child_nocopy (_locations->get_state());
1125 Locations loc (*this);
1126 // for a template, just create a new Locations, populate it
1127 // with the default start and end, and get the state for that.
1128 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1129 range->set (max_framepos, 0);
1131 XMLNode& locations_state = loc.get_state();
1133 if (ARDOUR::Profile->get_trx() && _locations) {
1134 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1135 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1136 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1137 locations_state.add_child_nocopy ((*i)->get_state ());
1141 node->add_child_nocopy (locations_state);
1144 child = node->add_child ("Bundles");
1146 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1147 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1148 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1150 child->add_child_nocopy (b->get_state());
1155 child = node->add_child ("Routes");
1157 boost::shared_ptr<RouteList> r = routes.reader ();
1159 RoutePublicOrderSorter cmp;
1160 RouteList public_order (*r);
1161 public_order.sort (cmp);
1163 /* the sort should have put control outs first */
1166 assert (_monitor_out == public_order.front());
1169 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1170 if (!(*i)->is_auditioner()) {
1172 child->add_child_nocopy ((*i)->get_state());
1174 child->add_child_nocopy ((*i)->get_template());
1180 playlists->add_state (node, full_state);
1182 child = node->add_child ("RouteGroups");
1183 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1184 child->add_child_nocopy ((*i)->get_state());
1188 XMLNode* gain_child = node->add_child ("Click");
1189 gain_child->add_child_nocopy (_click_io->state (full_state));
1190 gain_child->add_child_nocopy (_click_gain->state (full_state));
1194 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1195 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1199 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1200 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1203 node->add_child_nocopy (_speakers->get_state());
1204 node->add_child_nocopy (_tempo_map->get_state());
1205 node->add_child_nocopy (get_control_protocol_state());
1208 node->add_child_copy (*_extra_xml);
1215 Session::get_control_protocol_state ()
1217 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1218 return cpm.get_state();
1222 Session::set_state (const XMLNode& node, int version)
1226 const XMLProperty* prop;
1229 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1231 if (node.name() != X_("Session")) {
1232 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1236 if ((prop = node.property ("name")) != 0) {
1237 _name = prop->value ();
1240 if ((prop = node.property (X_("sample-rate"))) != 0) {
1242 _nominal_frame_rate = atoi (prop->value());
1244 if (_nominal_frame_rate != _current_frame_rate) {
1245 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1246 if (r.get_value_or (0)) {
1252 setup_raid_path(_session_dir->root_path());
1254 if ((prop = node.property (X_("id-counter"))) != 0) {
1256 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1257 ID::init_counter (x);
1259 /* old sessions used a timebased counter, so fake
1260 the startup ID counter based on a standard
1265 ID::init_counter (now);
1268 if ((prop = node.property (X_("event-counter"))) != 0) {
1269 Evoral::init_event_id_counter (atoi (prop->value()));
1273 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1274 _midi_ports->set_midi_port_states (child->children());
1277 IO::disable_connecting ();
1279 Stateful::save_extra_xml (node);
1281 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1282 load_options (*child);
1283 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1284 load_options (*child);
1286 error << _("Session: XML state has no options section") << endmsg;
1289 if (version >= 3000) {
1290 if ((child = find_named_node (node, "Metadata")) == 0) {
1291 warning << _("Session: XML state has no metadata section") << endmsg;
1292 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1297 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1298 _speakers->set_state (*child, version);
1301 if ((child = find_named_node (node, "Sources")) == 0) {
1302 error << _("Session: XML state has no sources section") << endmsg;
1304 } else if (load_sources (*child)) {
1308 if ((child = find_named_node (node, "TempoMap")) == 0) {
1309 error << _("Session: XML state has no Tempo Map section") << endmsg;
1311 } else if (_tempo_map->set_state (*child, version)) {
1315 if ((child = find_named_node (node, "Locations")) == 0) {
1316 error << _("Session: XML state has no locations section") << endmsg;
1318 } else if (_locations->set_state (*child, version)) {
1322 locations_changed ();
1324 if (_session_range_location) {
1325 AudioFileSource::set_header_position_offset (_session_range_location->start());
1328 if ((child = find_named_node (node, "Regions")) == 0) {
1329 error << _("Session: XML state has no Regions section") << endmsg;
1331 } else if (load_regions (*child)) {
1335 if ((child = find_named_node (node, "Playlists")) == 0) {
1336 error << _("Session: XML state has no playlists section") << endmsg;
1338 } else if (playlists->load (*this, *child)) {
1342 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1344 } else if (playlists->load_unused (*this, *child)) {
1348 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1349 if (load_compounds (*child)) {
1354 if (version >= 3000) {
1355 if ((child = find_named_node (node, "Bundles")) == 0) {
1356 warning << _("Session: XML state has no bundles section") << endmsg;
1359 /* We can't load Bundles yet as they need to be able
1360 to convert from port names to Port objects, which can't happen until
1362 _bundle_xml_node = new XMLNode (*child);
1366 if (version < 3000) {
1367 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1368 error << _("Session: XML state has no diskstreams section") << endmsg;
1370 } else if (load_diskstreams_2X (*child, version)) {
1375 if ((child = find_named_node (node, "Routes")) == 0) {
1376 error << _("Session: XML state has no routes section") << endmsg;
1378 } else if (load_routes (*child, version)) {
1382 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1383 _diskstreams_2X.clear ();
1385 if (version >= 3000) {
1387 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1388 error << _("Session: XML state has no route groups section") << endmsg;
1390 } else if (load_route_groups (*child, version)) {
1394 } else if (version < 3000) {
1396 if ((child = find_named_node (node, "EditGroups")) == 0) {
1397 error << _("Session: XML state has no edit groups section") << endmsg;
1399 } else if (load_route_groups (*child, version)) {
1403 if ((child = find_named_node (node, "MixGroups")) == 0) {
1404 error << _("Session: XML state has no mix groups section") << endmsg;
1406 } else if (load_route_groups (*child, version)) {
1411 if ((child = find_named_node (node, "Click")) == 0) {
1412 warning << _("Session: XML state has no click section") << endmsg;
1413 } else if (_click_io) {
1414 setup_click_state (&node);
1417 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1418 ControlProtocolManager::instance().set_state (*child, version);
1421 update_route_record_state ();
1423 /* here beginneth the second phase ... */
1425 StateReady (); /* EMIT SIGNAL */
1438 Session::load_routes (const XMLNode& node, int version)
1441 XMLNodeConstIterator niter;
1442 RouteList new_routes;
1444 nlist = node.children();
1448 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1450 boost::shared_ptr<Route> route;
1451 if (version < 3000) {
1452 route = XMLRouteFactory_2X (**niter, version);
1454 route = XMLRouteFactory (**niter, version);
1458 error << _("Session: cannot create Route from XML description.") << endmsg;
1462 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1464 new_routes.push_back (route);
1467 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1469 add_routes (new_routes, false, false, false);
1471 BootMessage (_("Finished adding tracks/busses"));
1476 boost::shared_ptr<Route>
1477 Session::XMLRouteFactory (const XMLNode& node, int version)
1479 boost::shared_ptr<Route> ret;
1481 if (node.name() != "Route") {
1485 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1487 DataType type = DataType::AUDIO;
1488 const XMLProperty* prop = node.property("default-type");
1491 type = DataType (prop->value());
1494 assert (type != DataType::NIL);
1498 boost::shared_ptr<Track> track;
1500 if (type == DataType::AUDIO) {
1501 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1503 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1506 if (track->init()) {
1510 if (track->set_state (node, version)) {
1514 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1515 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1520 enum Route::Flag flags = Route::Flag(0);
1521 const XMLProperty* prop = node.property("flags");
1523 flags = Route::Flag (string_2_enum (prop->value(), flags));
1526 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1528 if (r->init () == 0 && r->set_state (node, version) == 0) {
1529 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1530 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1539 boost::shared_ptr<Route>
1540 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1542 boost::shared_ptr<Route> ret;
1544 if (node.name() != "Route") {
1548 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1550 ds_prop = node.property (X_("diskstream"));
1553 DataType type = DataType::AUDIO;
1554 const XMLProperty* prop = node.property("default-type");
1557 type = DataType (prop->value());
1560 assert (type != DataType::NIL);
1564 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1565 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1569 if (i == _diskstreams_2X.end()) {
1570 error << _("Could not find diskstream for route") << endmsg;
1571 return boost::shared_ptr<Route> ();
1574 boost::shared_ptr<Track> track;
1576 if (type == DataType::AUDIO) {
1577 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1579 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1582 if (track->init()) {
1586 if (track->set_state (node, version)) {
1590 track->set_diskstream (*i);
1592 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1593 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1598 enum Route::Flag flags = Route::Flag(0);
1599 const XMLProperty* prop = node.property("flags");
1601 flags = Route::Flag (string_2_enum (prop->value(), flags));
1604 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1606 if (r->init () == 0 && r->set_state (node, version) == 0) {
1607 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1608 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1618 Session::load_regions (const XMLNode& node)
1621 XMLNodeConstIterator niter;
1622 boost::shared_ptr<Region> region;
1624 nlist = node.children();
1628 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1629 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1630 error << _("Session: cannot create Region from XML description.");
1631 const XMLProperty *name = (**niter).property("name");
1634 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1645 Session::load_compounds (const XMLNode& node)
1647 XMLNodeList calist = node.children();
1648 XMLNodeConstIterator caiter;
1649 XMLProperty *caprop;
1651 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1652 XMLNode* ca = *caiter;
1656 if ((caprop = ca->property (X_("original"))) == 0) {
1659 orig_id = caprop->value();
1661 if ((caprop = ca->property (X_("copy"))) == 0) {
1664 copy_id = caprop->value();
1666 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1667 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1669 if (!orig || !copy) {
1670 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1676 RegionFactory::add_compound_association (orig, copy);
1683 Session::load_nested_sources (const XMLNode& node)
1686 XMLNodeConstIterator niter;
1688 nlist = node.children();
1690 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1691 if ((*niter)->name() == "Source") {
1693 /* it may already exist, so don't recreate it unnecessarily
1696 XMLProperty* prop = (*niter)->property (X_("id"));
1698 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1702 ID source_id (prop->value());
1704 if (!source_by_id (source_id)) {
1707 SourceFactory::create (*this, **niter, true);
1709 catch (failed_constructor& err) {
1710 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1717 boost::shared_ptr<Region>
1718 Session::XMLRegionFactory (const XMLNode& node, bool full)
1720 const XMLProperty* type = node.property("type");
1724 const XMLNodeList& nlist = node.children();
1726 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1727 XMLNode *child = (*niter);
1728 if (child->name() == "NestedSource") {
1729 load_nested_sources (*child);
1733 if (!type || type->value() == "audio") {
1734 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1735 } else if (type->value() == "midi") {
1736 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1739 } catch (failed_constructor& err) {
1740 return boost::shared_ptr<Region> ();
1743 return boost::shared_ptr<Region> ();
1746 boost::shared_ptr<AudioRegion>
1747 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1749 const XMLProperty* prop;
1750 boost::shared_ptr<Source> source;
1751 boost::shared_ptr<AudioSource> as;
1753 SourceList master_sources;
1754 uint32_t nchans = 1;
1757 if (node.name() != X_("Region")) {
1758 return boost::shared_ptr<AudioRegion>();
1761 if ((prop = node.property (X_("channels"))) != 0) {
1762 nchans = atoi (prop->value().c_str());
1765 if ((prop = node.property ("name")) == 0) {
1766 cerr << "no name for this region\n";
1770 if ((prop = node.property (X_("source-0"))) == 0) {
1771 if ((prop = node.property ("source")) == 0) {
1772 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1773 return boost::shared_ptr<AudioRegion>();
1777 PBD::ID s_id (prop->value());
1779 if ((source = source_by_id (s_id)) == 0) {
1780 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1781 return boost::shared_ptr<AudioRegion>();
1784 as = boost::dynamic_pointer_cast<AudioSource>(source);
1786 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1787 return boost::shared_ptr<AudioRegion>();
1790 sources.push_back (as);
1792 /* pickup other channels */
1794 for (uint32_t n=1; n < nchans; ++n) {
1795 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1796 if ((prop = node.property (buf)) != 0) {
1798 PBD::ID id2 (prop->value());
1800 if ((source = source_by_id (id2)) == 0) {
1801 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1802 return boost::shared_ptr<AudioRegion>();
1805 as = boost::dynamic_pointer_cast<AudioSource>(source);
1807 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1808 return boost::shared_ptr<AudioRegion>();
1810 sources.push_back (as);
1814 for (uint32_t n = 0; n < nchans; ++n) {
1815 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1816 if ((prop = node.property (buf)) != 0) {
1818 PBD::ID id2 (prop->value());
1820 if ((source = source_by_id (id2)) == 0) {
1821 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1822 return boost::shared_ptr<AudioRegion>();
1825 as = boost::dynamic_pointer_cast<AudioSource>(source);
1827 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1828 return boost::shared_ptr<AudioRegion>();
1830 master_sources.push_back (as);
1835 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1837 /* a final detail: this is the one and only place that we know how long missing files are */
1839 if (region->whole_file()) {
1840 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1841 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1843 sfp->set_length (region->length());
1848 if (!master_sources.empty()) {
1849 if (master_sources.size() != nchans) {
1850 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1852 region->set_master_sources (master_sources);
1860 catch (failed_constructor& err) {
1861 return boost::shared_ptr<AudioRegion>();
1865 boost::shared_ptr<MidiRegion>
1866 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1868 const XMLProperty* prop;
1869 boost::shared_ptr<Source> source;
1870 boost::shared_ptr<MidiSource> ms;
1873 if (node.name() != X_("Region")) {
1874 return boost::shared_ptr<MidiRegion>();
1877 if ((prop = node.property ("name")) == 0) {
1878 cerr << "no name for this region\n";
1882 if ((prop = node.property (X_("source-0"))) == 0) {
1883 if ((prop = node.property ("source")) == 0) {
1884 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1885 return boost::shared_ptr<MidiRegion>();
1889 PBD::ID s_id (prop->value());
1891 if ((source = source_by_id (s_id)) == 0) {
1892 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1893 return boost::shared_ptr<MidiRegion>();
1896 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1898 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1899 return boost::shared_ptr<MidiRegion>();
1902 sources.push_back (ms);
1905 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1906 /* a final detail: this is the one and only place that we know how long missing files are */
1908 if (region->whole_file()) {
1909 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1910 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1912 sfp->set_length (region->length());
1920 catch (failed_constructor& err) {
1921 return boost::shared_ptr<MidiRegion>();
1926 Session::get_sources_as_xml ()
1929 XMLNode* node = new XMLNode (X_("Sources"));
1930 Glib::Threads::Mutex::Lock lm (source_lock);
1932 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1933 node->add_child_nocopy (i->second->get_state());
1940 Session::reset_write_sources (bool mark_write_complete, bool force)
1942 boost::shared_ptr<RouteList> rl = routes.reader();
1943 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1944 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1946 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1947 tr->reset_write_sources(mark_write_complete, force);
1948 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1954 Session::load_sources (const XMLNode& node)
1957 XMLNodeConstIterator niter;
1958 boost::shared_ptr<Source> source; /* don't need this but it stops some
1959 * versions of gcc complaining about
1960 * discarded return values.
1963 nlist = node.children();
1967 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1970 if ((source = XMLSourceFactory (**niter)) == 0) {
1971 error << _("Session: cannot create Source from XML description.") << endmsg;
1974 } catch (MissingSource& err) {
1978 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1979 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1980 PROGRAM_NAME) << endmsg;
1984 if (!no_questions_about_missing_files) {
1985 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1990 switch (user_choice) {
1992 /* user added a new search location, so try again */
1997 /* user asked to quit the entire session load
2002 no_questions_about_missing_files = true;
2006 no_questions_about_missing_files = true;
2013 case DataType::AUDIO:
2014 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2017 case DataType::MIDI:
2018 /* The MIDI file is actually missing so
2019 * just create a new one in the same
2020 * location. Do not announce its
2024 if (!Glib::path_is_absolute (err.path)) {
2025 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2027 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2032 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2033 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2034 /* reset ID to match the missing one */
2035 source->set_id (**niter);
2036 /* Now we can announce it */
2037 SourceFactory::SourceCreated (source);
2048 boost::shared_ptr<Source>
2049 Session::XMLSourceFactory (const XMLNode& node)
2051 if (node.name() != "Source") {
2052 return boost::shared_ptr<Source>();
2056 /* note: do peak building in another thread when loading session state */
2057 return SourceFactory::create (*this, node, true);
2060 catch (failed_constructor& err) {
2061 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2062 return boost::shared_ptr<Source>();
2067 Session::save_template (string template_name)
2069 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2073 bool absolute_path = Glib::path_is_absolute (template_name);
2075 /* directory to put the template in */
2076 std::string template_dir_path;
2078 if (!absolute_path) {
2079 std::string user_template_dir(user_template_directory());
2081 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2082 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2083 user_template_dir, g_strerror (errno)) << endmsg;
2087 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2089 template_dir_path = template_name;
2092 if (!ARDOUR::Profile->get_trx()) {
2093 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2094 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2095 template_dir_path) << endmsg;
2099 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2100 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2101 template_dir_path, g_strerror (errno)) << endmsg;
2107 std::string template_file_path;
2109 if (ARDOUR::Profile->get_trx()) {
2110 template_file_path = template_name;
2112 if (absolute_path) {
2113 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2115 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2119 SessionSaveUnderway (); /* EMIT SIGNAL */
2123 tree.set_root (&get_template());
2124 if (!tree.write (template_file_path)) {
2125 error << _("template not saved") << endmsg;
2129 if (!ARDOUR::Profile->get_trx()) {
2130 /* copy plugin state directory */
2132 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2134 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2135 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2136 template_plugin_state_path, g_strerror (errno)) << endmsg;
2139 copy_files (plugins_dir(), template_plugin_state_path);
2142 store_recent_templates (template_file_path);
2148 Session::refresh_disk_space ()
2150 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2152 Glib::Threads::Mutex::Lock lm (space_lock);
2154 /* get freespace on every FS that is part of the session path */
2156 _total_free_4k_blocks = 0;
2157 _total_free_4k_blocks_uncertain = false;
2159 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2161 struct statfs statfsbuf;
2162 statfs (i->path.c_str(), &statfsbuf);
2164 double const scale = statfsbuf.f_bsize / 4096.0;
2166 /* See if this filesystem is read-only */
2167 struct statvfs statvfsbuf;
2168 statvfs (i->path.c_str(), &statvfsbuf);
2170 /* f_bavail can be 0 if it is undefined for whatever
2171 filesystem we are looking at; Samba shares mounted
2172 via GVFS are an example of this.
2174 if (statfsbuf.f_bavail == 0) {
2175 /* block count unknown */
2177 i->blocks_unknown = true;
2178 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2179 /* read-only filesystem */
2181 i->blocks_unknown = false;
2183 /* read/write filesystem with known space */
2184 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2185 i->blocks_unknown = false;
2188 _total_free_4k_blocks += i->blocks;
2189 if (i->blocks_unknown) {
2190 _total_free_4k_blocks_uncertain = true;
2193 #elif defined PLATFORM_WINDOWS
2194 vector<string> scanned_volumes;
2195 vector<string>::iterator j;
2196 vector<space_and_path>::iterator i;
2197 DWORD nSectorsPerCluster, nBytesPerSector,
2198 nFreeClusters, nTotalClusters;
2202 _total_free_4k_blocks = 0;
2204 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2205 strncpy (disk_drive, (*i).path.c_str(), 3);
2209 volume_found = false;
2210 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2212 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2213 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2214 i->blocks = (uint32_t)(nFreeBytes / 4096);
2216 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2217 if (0 == j->compare(disk_drive)) {
2218 volume_found = true;
2223 if (!volume_found) {
2224 scanned_volumes.push_back(disk_drive);
2225 _total_free_4k_blocks += i->blocks;
2230 if (0 == _total_free_4k_blocks) {
2231 strncpy (disk_drive, path().c_str(), 3);
2234 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2236 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2237 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2238 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2245 Session::get_best_session_directory_for_new_audio ()
2247 vector<space_and_path>::iterator i;
2248 string result = _session_dir->root_path();
2250 /* handle common case without system calls */
2252 if (session_dirs.size() == 1) {
2256 /* OK, here's the algorithm we're following here:
2258 We want to select which directory to use for
2259 the next file source to be created. Ideally,
2260 we'd like to use a round-robin process so as to
2261 get maximum performance benefits from splitting
2262 the files across multiple disks.
2264 However, in situations without much diskspace, an
2265 RR approach may end up filling up a filesystem
2266 with new files while others still have space.
2267 Its therefore important to pay some attention to
2268 the freespace in the filesystem holding each
2269 directory as well. However, if we did that by
2270 itself, we'd keep creating new files in the file
2271 system with the most space until it was as full
2272 as all others, thus negating any performance
2273 benefits of this RAID-1 like approach.
2275 So, we use a user-configurable space threshold. If
2276 there are at least 2 filesystems with more than this
2277 much space available, we use RR selection between them.
2278 If not, then we pick the filesystem with the most space.
2280 This gets a good balance between the two
2284 refresh_disk_space ();
2286 int free_enough = 0;
2288 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2289 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2294 if (free_enough >= 2) {
2295 /* use RR selection process, ensuring that the one
2299 i = last_rr_session_dir;
2302 if (++i == session_dirs.end()) {
2303 i = session_dirs.begin();
2306 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2307 SessionDirectory sdir(i->path);
2308 if (sdir.create ()) {
2310 last_rr_session_dir = i;
2315 } while (i != last_rr_session_dir);
2319 /* pick FS with the most freespace (and that
2320 seems to actually work ...)
2323 vector<space_and_path> sorted;
2324 space_and_path_ascending_cmp cmp;
2326 sorted = session_dirs;
2327 sort (sorted.begin(), sorted.end(), cmp);
2329 for (i = sorted.begin(); i != sorted.end(); ++i) {
2330 SessionDirectory sdir(i->path);
2331 if (sdir.create ()) {
2333 last_rr_session_dir = i;
2343 Session::automation_dir () const
2345 return Glib::build_filename (_path, automation_dir_name);
2349 Session::analysis_dir () const
2351 return Glib::build_filename (_path, analysis_dir_name);
2355 Session::plugins_dir () const
2357 return Glib::build_filename (_path, plugins_dir_name);
2361 Session::externals_dir () const
2363 return Glib::build_filename (_path, externals_dir_name);
2367 Session::load_bundles (XMLNode const & node)
2369 XMLNodeList nlist = node.children();
2370 XMLNodeConstIterator niter;
2374 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2375 if ((*niter)->name() == "InputBundle") {
2376 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2377 } else if ((*niter)->name() == "OutputBundle") {
2378 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2380 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2389 Session::load_route_groups (const XMLNode& node, int version)
2391 XMLNodeList nlist = node.children();
2392 XMLNodeConstIterator niter;
2396 if (version >= 3000) {
2398 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2399 if ((*niter)->name() == "RouteGroup") {
2400 RouteGroup* rg = new RouteGroup (*this, "");
2401 add_route_group (rg);
2402 rg->set_state (**niter, version);
2406 } else if (version < 3000) {
2408 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2409 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2410 RouteGroup* rg = new RouteGroup (*this, "");
2411 add_route_group (rg);
2412 rg->set_state (**niter, version);
2421 state_file_filter (const string &str, void* /*arg*/)
2423 return (str.length() > strlen(statefile_suffix) &&
2424 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2428 remove_end(string state)
2430 string statename(state);
2432 string::size_type start,end;
2433 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2434 statename = statename.substr (start+1);
2437 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2438 end = statename.length();
2441 return string(statename.substr (0, end));
2445 Session::possible_states (string path)
2447 vector<string> states;
2448 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2450 transform(states.begin(), states.end(), states.begin(), remove_end);
2452 sort (states.begin(), states.end());
2458 Session::possible_states () const
2460 return possible_states(_path);
2464 Session::add_route_group (RouteGroup* g)
2466 _route_groups.push_back (g);
2467 route_group_added (g); /* EMIT SIGNAL */
2469 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2470 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2471 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2477 Session::remove_route_group (RouteGroup& rg)
2479 list<RouteGroup*>::iterator i;
2481 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2482 _route_groups.erase (i);
2485 route_group_removed (); /* EMIT SIGNAL */
2489 /** Set a new order for our route groups, without adding or removing any.
2490 * @param groups Route group list in the new order.
2493 Session::reorder_route_groups (list<RouteGroup*> groups)
2495 _route_groups = groups;
2497 route_groups_reordered (); /* EMIT SIGNAL */
2503 Session::route_group_by_name (string name)
2505 list<RouteGroup *>::iterator i;
2507 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2508 if ((*i)->name() == name) {
2516 Session::all_route_group() const
2518 return *_all_route_group;
2522 Session::add_commands (vector<Command*> const & cmds)
2524 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2530 Session::begin_reversible_command (const string& name)
2532 begin_reversible_command (g_quark_from_string (name.c_str ()));
2535 /** Begin a reversible command using a GQuark to identify it.
2536 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2537 * but there must be as many begin...()s as there are commit...()s.
2540 Session::begin_reversible_command (GQuark q)
2542 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2543 to hold all the commands that are committed. This keeps the order of
2544 commands correct in the history.
2547 if (_current_trans == 0) {
2548 /* start a new transaction */
2549 assert (_current_trans_quarks.empty ());
2550 _current_trans = new UndoTransaction();
2551 _current_trans->set_name (g_quark_to_string (q));
2554 _current_trans_quarks.push_front (q);
2558 Session::abort_reversible_command ()
2560 if (_current_trans != 0) {
2561 _current_trans->clear();
2562 delete _current_trans;
2564 _current_trans_quarks.clear();
2569 Session::commit_reversible_command (Command *cmd)
2571 assert (_current_trans);
2572 assert (!_current_trans_quarks.empty ());
2577 _current_trans->add_command (cmd);
2580 _current_trans_quarks.pop_front ();
2582 if (!_current_trans_quarks.empty ()) {
2583 /* the transaction we're committing is not the top-level one */
2587 if (_current_trans->empty()) {
2588 /* no commands were added to the transaction, so just get rid of it */
2589 delete _current_trans;
2594 gettimeofday (&now, 0);
2595 _current_trans->set_timestamp (now);
2597 _history.add (_current_trans);
2602 accept_all_audio_files (const string& path, void* /*arg*/)
2604 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2608 if (!AudioFileSource::safe_audio_file_extension (path)) {
2616 accept_all_midi_files (const string& path, void* /*arg*/)
2618 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2622 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2623 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2624 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2628 accept_all_state_files (const string& path, void* /*arg*/)
2630 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2634 std::string const statefile_ext (statefile_suffix);
2635 if (path.length() >= statefile_ext.length()) {
2636 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2643 Session::find_all_sources (string path, set<string>& result)
2648 if (!tree.read (path)) {
2652 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2657 XMLNodeConstIterator niter;
2659 nlist = node->children();
2663 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2667 if ((prop = (*niter)->property (X_("type"))) == 0) {
2671 DataType type (prop->value());
2673 if ((prop = (*niter)->property (X_("name"))) == 0) {
2677 if (Glib::path_is_absolute (prop->value())) {
2678 /* external file, ignore */
2686 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2687 result.insert (found_path);
2695 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2697 vector<string> state_files;
2699 string this_snapshot_path;
2705 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2706 ripped = ripped.substr (0, ripped.length() - 1);
2709 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2711 if (state_files.empty()) {
2716 this_snapshot_path = _path;
2717 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2718 this_snapshot_path += statefile_suffix;
2720 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2722 if (exclude_this_snapshot && *i == this_snapshot_path) {
2726 if (find_all_sources (*i, result) < 0) {
2734 struct RegionCounter {
2735 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2736 AudioSourceList::iterator iter;
2737 boost::shared_ptr<Region> region;
2740 RegionCounter() : count (0) {}
2744 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2746 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2747 return r.get_value_or (1);
2751 Session::cleanup_regions ()
2753 bool removed = false;
2754 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2756 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2758 uint32_t used = playlists->region_use_count (i->second);
2760 if (used == 0 && !i->second->automatic ()) {
2762 RegionFactory::map_remove (i->second);
2767 // re-check to remove parent references of compound regions
2768 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2769 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2772 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2773 if (0 == playlists->region_use_count (i->second)) {
2774 RegionFactory::map_remove (i->second);
2779 /* dump the history list */
2786 Session::cleanup_sources (CleanupReport& rep)
2788 // FIXME: needs adaptation to midi
2790 vector<boost::shared_ptr<Source> > dead_sources;
2793 vector<string> candidates;
2794 vector<string> unused;
2795 set<string> all_sources;
2804 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2806 /* consider deleting all unused playlists */
2808 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2813 /* sync the "all regions" property of each playlist with its current state
2816 playlists->sync_all_regions_with_regions ();
2818 /* find all un-used sources */
2823 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2825 SourceMap::iterator tmp;
2830 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2834 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2835 dead_sources.push_back (i->second);
2836 i->second->drop_references ();
2842 /* build a list of all the possible audio directories for the session */
2844 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2845 SessionDirectory sdir ((*i).path);
2846 asp += sdir.sound_path();
2848 audio_path += asp.to_string();
2851 /* build a list of all the possible midi directories for the session */
2853 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2854 SessionDirectory sdir ((*i).path);
2855 msp += sdir.midi_path();
2857 midi_path += msp.to_string();
2859 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2860 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2862 /* find all sources, but don't use this snapshot because the
2863 state file on disk still references sources we may have already
2867 find_all_sources_across_snapshots (all_sources, true);
2869 /* add our current source list
2872 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2873 boost::shared_ptr<FileSource> fs;
2874 SourceMap::iterator tmp = i;
2877 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2879 if (!fs->is_stub()) {
2881 if (playlists->source_use_count (fs) != 0) {
2882 all_sources.insert (fs->path());
2885 /* we might not remove this source from disk, because it may be used
2886 by other snapshots, but its not being used in this version
2887 so lets get rid of it now, along with any representative regions
2891 std::string fpath = i->second->name ();
2893 RegionFactory::remove_regions_using_source (i->second);
2896 // also remove source from all_sources
2898 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2899 spath = Glib::path_get_basename (*j);
2900 if ( spath == fpath ) {
2901 all_sources.erase (j);
2912 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2917 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2919 tmppath1 = canonical_path (spath);
2920 tmppath2 = canonical_path ((*i));
2922 if (tmppath1 == tmppath2) {
2929 unused.push_back (spath);
2933 /* now try to move all unused files into the "dead" directory(ies) */
2935 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2936 struct stat statbuf;
2940 /* don't move the file across filesystems, just
2941 stick it in the `dead_dir_name' directory
2942 on whichever filesystem it was already on.
2945 if ((*x).find ("/sounds/") != string::npos) {
2947 /* old school, go up 1 level */
2949 newpath = Glib::path_get_dirname (*x); // "sounds"
2950 newpath = Glib::path_get_dirname (newpath); // "session-name"
2954 /* new school, go up 4 levels */
2956 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2957 newpath = Glib::path_get_dirname (newpath); // "session-name"
2958 newpath = Glib::path_get_dirname (newpath); // "interchange"
2959 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2962 newpath = Glib::build_filename (newpath, dead_dir_name);
2964 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2965 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2969 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2971 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2973 /* the new path already exists, try versioning */
2975 char buf[PATH_MAX+1];
2979 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2982 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2983 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2987 if (version == 999) {
2988 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2992 newpath = newpath_v;
2997 /* it doesn't exist, or we can't read it or something */
3001 stat ((*x).c_str(), &statbuf);
3003 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3004 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3005 (*x), newpath, strerror (errno))
3010 /* see if there an easy to find peakfile for this file, and remove it.
3013 string base = basename_nosuffix (*x);
3014 base += "%A"; /* this is what we add for the channel suffix of all native files,
3015 or for the first channel of embedded files. it will miss
3016 some peakfiles for other channels
3018 string peakpath = peak_path (base);
3020 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3021 if (::g_unlink (peakpath.c_str()) != 0) {
3022 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3023 peakpath, _path, strerror (errno))
3025 /* try to back out */
3026 ::rename (newpath.c_str(), _path.c_str());
3031 rep.paths.push_back (*x);
3032 rep.space += statbuf.st_size;
3035 /* dump the history list */
3039 /* save state so we don't end up a session file
3040 referring to non-existent sources.
3047 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3053 Session::cleanup_trash_sources (CleanupReport& rep)
3055 // FIXME: needs adaptation for MIDI
3057 vector<space_and_path>::iterator i;
3063 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3065 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3067 clear_directory (dead_dir, &rep.space, &rep.paths);
3074 Session::set_dirty ()
3076 /* never mark session dirty during loading */
3078 if (_state_of_the_state & Loading) {
3082 bool was_dirty = dirty();
3084 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3088 DirtyChanged(); /* EMIT SIGNAL */
3094 Session::set_clean ()
3096 bool was_dirty = dirty();
3098 _state_of_the_state = Clean;
3102 DirtyChanged(); /* EMIT SIGNAL */
3107 Session::set_deletion_in_progress ()
3109 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3113 Session::clear_deletion_in_progress ()
3115 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3119 Session::add_controllable (boost::shared_ptr<Controllable> c)
3121 /* this adds a controllable to the list managed by the Session.
3122 this is a subset of those managed by the Controllable class
3123 itself, and represents the only ones whose state will be saved
3124 as part of the session.
3127 Glib::Threads::Mutex::Lock lm (controllables_lock);
3128 controllables.insert (c);
3131 struct null_deleter { void operator()(void const *) const {} };
3134 Session::remove_controllable (Controllable* c)
3136 if (_state_of_the_state & Deletion) {
3140 Glib::Threads::Mutex::Lock lm (controllables_lock);
3142 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3144 if (x != controllables.end()) {
3145 controllables.erase (x);
3149 boost::shared_ptr<Controllable>
3150 Session::controllable_by_id (const PBD::ID& id)
3152 Glib::Threads::Mutex::Lock lm (controllables_lock);
3154 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3155 if ((*i)->id() == id) {
3160 return boost::shared_ptr<Controllable>();
3163 boost::shared_ptr<Controllable>
3164 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3166 boost::shared_ptr<Controllable> c;
3167 boost::shared_ptr<Route> r;
3169 switch (desc.top_level_type()) {
3170 case ControllableDescriptor::NamedRoute:
3172 std::string str = desc.top_level_name();
3173 if (str == "Master" || str == "master") {
3175 } else if (str == "control" || str == "listen") {
3178 r = route_by_name (desc.top_level_name());
3183 case ControllableDescriptor::RemoteControlID:
3184 r = route_by_remote_id (desc.rid());
3192 switch (desc.subtype()) {
3193 case ControllableDescriptor::Gain:
3194 c = r->gain_control ();
3197 case ControllableDescriptor::Trim:
3198 c = r->trim()->gain_control ();
3201 case ControllableDescriptor::Solo:
3202 c = r->solo_control();
3205 case ControllableDescriptor::Mute:
3206 c = r->mute_control();
3209 case ControllableDescriptor::Recenable:
3211 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3214 c = t->rec_enable_control ();
3219 case ControllableDescriptor::PanDirection:
3221 c = r->pannable()->pan_azimuth_control;
3225 case ControllableDescriptor::PanWidth:
3227 c = r->pannable()->pan_width_control;
3231 case ControllableDescriptor::PanElevation:
3233 c = r->pannable()->pan_elevation_control;
3237 case ControllableDescriptor::Balance:
3238 /* XXX simple pan control */
3241 case ControllableDescriptor::PluginParameter:
3243 uint32_t plugin = desc.target (0);
3244 uint32_t parameter_index = desc.target (1);
3246 /* revert to zero based counting */
3252 if (parameter_index > 0) {
3256 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3259 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3260 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3265 case ControllableDescriptor::SendGain:
3267 uint32_t send = desc.target (0);
3269 /* revert to zero-based counting */
3275 boost::shared_ptr<Processor> p = r->nth_send (send);
3278 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3279 boost::shared_ptr<Amp> a = s->amp();
3282 c = s->amp()->gain_control();
3289 /* relax and return a null pointer */
3297 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3300 Stateful::add_instant_xml (node, _path);
3303 if (write_to_config) {
3304 Config->add_instant_xml (node);
3309 Session::instant_xml (const string& node_name)
3311 return Stateful::instant_xml (node_name, _path);
3315 Session::save_history (string snapshot_name)
3323 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3324 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3328 if (snapshot_name.empty()) {
3329 snapshot_name = _current_snapshot_name;
3332 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3333 const string backup_filename = history_filename + backup_suffix;
3334 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3335 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3337 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3338 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3339 error << _("could not backup old history file, current history not saved") << endmsg;
3344 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3346 if (!tree.write (xml_path))
3348 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3350 if (g_remove (xml_path.c_str()) != 0) {
3351 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3352 xml_path, g_strerror (errno)) << endmsg;
3354 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3355 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3356 backup_path, g_strerror (errno)) << endmsg;
3366 Session::restore_history (string snapshot_name)
3370 if (snapshot_name.empty()) {
3371 snapshot_name = _current_snapshot_name;
3374 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3375 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3377 info << "Loading history from " << xml_path << endmsg;
3379 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3380 info << string_compose (_("%1: no history file \"%2\" for this session."),
3381 _name, xml_path) << endmsg;
3385 if (!tree.read (xml_path)) {
3386 error << string_compose (_("Could not understand session history file \"%1\""),
3387 xml_path) << endmsg;
3394 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3397 UndoTransaction* ut = new UndoTransaction ();
3400 ut->set_name(t->property("name")->value());
3401 stringstream ss(t->property("tv-sec")->value());
3403 ss.str(t->property("tv-usec")->value());
3405 ut->set_timestamp(tv);
3407 for (XMLNodeConstIterator child_it = t->children().begin();
3408 child_it != t->children().end(); child_it++)
3410 XMLNode *n = *child_it;
3413 if (n->name() == "MementoCommand" ||
3414 n->name() == "MementoUndoCommand" ||
3415 n->name() == "MementoRedoCommand") {
3417 if ((c = memento_command_factory(n))) {
3421 } else if (n->name() == "NoteDiffCommand") {
3422 PBD::ID id (n->property("midi-source")->value());
3423 boost::shared_ptr<MidiSource> midi_source =
3424 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3426 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3428 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3431 } else if (n->name() == "SysExDiffCommand") {
3433 PBD::ID id (n->property("midi-source")->value());
3434 boost::shared_ptr<MidiSource> midi_source =
3435 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3437 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3439 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3442 } else if (n->name() == "PatchChangeDiffCommand") {
3444 PBD::ID id (n->property("midi-source")->value());
3445 boost::shared_ptr<MidiSource> midi_source =
3446 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3448 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3450 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3453 } else if (n->name() == "StatefulDiffCommand") {
3454 if ((c = stateful_diff_command_factory (n))) {
3455 ut->add_command (c);
3458 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3469 Session::config_changed (std::string p, bool ours)
3475 if (p == "seamless-loop") {
3477 } else if (p == "rf-speed") {
3479 } else if (p == "auto-loop") {
3481 } else if (p == "auto-input") {
3483 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3484 /* auto-input only makes a difference if we're rolling */
3485 set_track_monitor_input_status (!config.get_auto_input());
3488 } else if (p == "punch-in") {
3492 if ((location = _locations->auto_punch_location()) != 0) {
3494 if (config.get_punch_in ()) {
3495 replace_event (SessionEvent::PunchIn, location->start());
3497 remove_event (location->start(), SessionEvent::PunchIn);
3501 } else if (p == "punch-out") {
3505 if ((location = _locations->auto_punch_location()) != 0) {
3507 if (config.get_punch_out()) {
3508 replace_event (SessionEvent::PunchOut, location->end());
3510 clear_events (SessionEvent::PunchOut);
3514 } else if (p == "edit-mode") {
3516 Glib::Threads::Mutex::Lock lm (playlists->lock);
3518 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3519 (*i)->set_edit_mode (Config->get_edit_mode ());
3522 } else if (p == "use-video-sync") {
3524 waiting_for_sync_offset = config.get_use_video_sync();
3526 } else if (p == "mmc-control") {
3528 //poke_midi_thread ();
3530 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3532 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3534 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3536 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3538 } else if (p == "midi-control") {
3540 //poke_midi_thread ();
3542 } else if (p == "raid-path") {
3544 setup_raid_path (config.get_raid_path());
3546 } else if (p == "timecode-format") {
3550 } else if (p == "video-pullup") {
3554 } else if (p == "seamless-loop") {
3556 if (play_loop && transport_rolling()) {
3557 // to reset diskstreams etc
3558 request_play_loop (true);
3561 } else if (p == "rf-speed") {
3563 cumulative_rf_motion = 0;
3566 } else if (p == "click-sound") {
3568 setup_click_sounds (1);
3570 } else if (p == "click-emphasis-sound") {
3572 setup_click_sounds (-1);
3574 } else if (p == "clicking") {
3576 if (Config->get_clicking()) {
3577 if (_click_io && click_data) { // don't require emphasis data
3584 } else if (p == "click-gain") {
3587 _click_gain->set_gain (Config->get_click_gain(), this);
3590 } else if (p == "send-mtc") {
3592 if (Config->get_send_mtc ()) {
3593 /* mark us ready to send */
3594 next_quarter_frame_to_send = 0;
3597 } else if (p == "send-mmc") {
3599 _mmc->enable_send (Config->get_send_mmc ());
3601 } else if (p == "midi-feedback") {
3603 session_midi_feedback = Config->get_midi_feedback();
3605 } else if (p == "jack-time-master") {
3607 engine().reset_timebase ();
3609 } else if (p == "native-file-header-format") {
3611 if (!first_file_header_format_reset) {
3612 reset_native_file_format ();
3615 first_file_header_format_reset = false;
3617 } else if (p == "native-file-data-format") {
3619 if (!first_file_data_format_reset) {
3620 reset_native_file_format ();
3623 first_file_data_format_reset = false;
3625 } else if (p == "external-sync") {
3626 if (!config.get_external_sync()) {
3627 drop_sync_source ();
3629 switch_to_sync_source (Config->get_sync_source());
3631 } else if (p == "denormal-model") {
3633 } else if (p == "history-depth") {
3634 set_history_depth (Config->get_history_depth());
3635 } else if (p == "remote-model") {
3636 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3639 } else if (p == "initial-program-change") {
3641 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3644 buf[0] = MIDI::program; // channel zero by default
3645 buf[1] = (Config->get_initial_program_change() & 0x7f);
3647 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3649 } else if (p == "solo-mute-override") {
3650 // catch_up_on_solo_mute_override ();
3651 } else if (p == "listen-position" || p == "pfl-position") {
3652 listen_position_changed ();
3653 } else if (p == "solo-control-is-listen-control") {
3654 solo_control_mode_changed ();
3655 } else if (p == "solo-mute-gain") {
3656 _solo_cut_control->Changed();
3657 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3658 last_timecode_valid = false;
3659 } else if (p == "playback-buffer-seconds") {
3660 AudioSource::allocate_working_buffers (frame_rate());
3661 } else if (p == "ltc-source-port") {
3662 reconnect_ltc_input ();
3663 } else if (p == "ltc-sink-port") {
3664 reconnect_ltc_output ();
3665 } else if (p == "timecode-generator-offset") {
3666 ltc_tx_parse_offset();
3667 } else if (p == "auto-return-target-list") {
3668 follow_playhead_priority ();
3675 Session::set_history_depth (uint32_t d)
3677 _history.set_depth (d);
3681 Session::load_diskstreams_2X (XMLNode const & node, int)
3684 XMLNodeConstIterator citer;
3686 clist = node.children();
3688 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3691 /* diskstreams added automatically by DiskstreamCreated handler */
3692 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3693 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3694 _diskstreams_2X.push_back (dsp);
3696 error << _("Session: unknown diskstream type in XML") << endmsg;
3700 catch (failed_constructor& err) {
3701 error << _("Session: could not load diskstream via XML state") << endmsg;
3709 /** Connect things to the MMC object */
3711 Session::setup_midi_machine_control ()
3713 _mmc = new MIDI::MachineControl;
3714 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3716 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3717 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3718 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3719 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3720 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3721 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3722 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3723 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3724 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3725 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3726 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3727 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3728 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3730 /* also handle MIDI SPP because its so common */
3732 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3733 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3734 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3737 boost::shared_ptr<Controllable>
3738 Session::solo_cut_control() const
3740 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3741 controls in Ardour that currently get presented to the user in the GUI that require
3742 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3744 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3745 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3749 return _solo_cut_control;
3753 Session::rename (const std::string& new_name)
3755 string legal_name = legalize_for_path (new_name);
3761 string const old_sources_root = _session_dir->sources_root();
3763 if (!_writable || (_state_of_the_state & CannotSave)) {
3764 error << _("Cannot rename read-only session.") << endmsg;
3765 return 0; // don't show "messed up" warning
3767 if (record_status() == Recording) {
3768 error << _("Cannot rename session while recording") << endmsg;
3769 return 0; // don't show "messed up" warning
3772 StateProtector stp (this);
3777 * interchange subdirectory
3781 * Backup files are left unchanged and not renamed.
3784 /* Windows requires that we close all files before attempting the
3785 * rename. This works on other platforms, but isn't necessary there.
3786 * Leave it in place for all platforms though, since it may help
3787 * catch issues that could arise if the way Source files work ever
3788 * change (since most developers are not using Windows).
3791 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3792 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3798 /* pass one: not 100% safe check that the new directory names don't
3802 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3806 /* this is a stupid hack because Glib::path_get_dirname() is
3807 * lexical-only, and so passing it /a/b/c/ gives a different
3808 * result than passing it /a/b/c ...
3811 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3812 oldstr = oldstr.substr (0, oldstr.length() - 1);
3815 string base = Glib::path_get_dirname (oldstr);
3817 newstr = Glib::build_filename (base, legal_name);
3819 cerr << "Looking for " << newstr << endl;
3821 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3822 cerr << " exists\n";
3831 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3837 /* this is a stupid hack because Glib::path_get_dirname() is
3838 * lexical-only, and so passing it /a/b/c/ gives a different
3839 * result than passing it /a/b/c ...
3842 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3843 oldstr = oldstr.substr (0, oldstr.length() - 1);
3846 string base = Glib::path_get_dirname (oldstr);
3847 newstr = Glib::build_filename (base, legal_name);
3849 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3851 cerr << "Rename " << oldstr << " => " << newstr << endl;
3852 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3853 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3854 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3858 /* Reset path in "session dirs" */
3863 /* reset primary SessionDirectory object */
3866 (*_session_dir) = newstr;
3871 /* now rename directory below session_dir/interchange */
3873 string old_interchange_dir;
3874 string new_interchange_dir;
3876 /* use newstr here because we renamed the path
3877 * (folder/directory) that used to be oldstr to newstr above
3880 v.push_back (newstr);
3881 v.push_back (interchange_dir_name);
3882 v.push_back (Glib::path_get_basename (oldstr));
3884 old_interchange_dir = Glib::build_filename (v);
3887 v.push_back (newstr);
3888 v.push_back (interchange_dir_name);
3889 v.push_back (legal_name);
3891 new_interchange_dir = Glib::build_filename (v);
3893 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3895 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3896 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3897 old_interchange_dir, new_interchange_dir,
3900 error << string_compose (_("renaming %s as %2 failed (%3)"),
3901 old_interchange_dir, new_interchange_dir,
3910 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3911 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3913 cerr << "Rename " << oldstr << " => " << newstr << endl;
3915 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3916 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3917 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3923 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3925 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3926 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3928 cerr << "Rename " << oldstr << " => " << newstr << endl;
3930 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3931 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3932 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3937 /* remove old name from recent sessions */
3938 remove_recent_sessions (_path);
3941 /* update file source paths */
3943 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3944 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3946 string p = fs->path ();
3947 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3949 SourceFactory::setup_peakfile(i->second, true);
3953 _current_snapshot_name = new_name;
3958 /* save state again to get everything just right */
3960 save_state (_current_snapshot_name);
3962 /* add to recent sessions */
3964 store_recent_sessions (new_name, _path);
3970 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3972 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3976 if (!tree.read (xmlpath)) {
3984 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3987 bool found_sr = false;
3988 bool found_data_format = false;
3990 if (get_session_info_from_path (tree, xmlpath)) {
3996 const XMLProperty* prop;
3997 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3998 sample_rate = atoi (prop->value());
4002 const XMLNodeList& children (tree.root()->children());
4003 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4004 const XMLNode* child = *c;
4005 if (child->name() == "Config") {
4006 const XMLNodeList& options (child->children());
4007 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4008 const XMLNode* option = *oc;
4009 const XMLProperty* name = option->property("name");
4015 if (name->value() == "native-file-data-format") {
4016 const XMLProperty* value = option->property ("value");
4018 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4020 found_data_format = true;
4026 if (found_data_format) {
4031 return !(found_sr && found_data_format); // zero if they are both found
4034 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4035 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4038 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4042 SourcePathMap source_path_map;
4044 boost::shared_ptr<AudioFileSource> afs;
4049 Glib::Threads::Mutex::Lock lm (source_lock);
4051 cerr << " total sources = " << sources.size();
4053 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4054 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4060 if (fs->within_session()) {
4064 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4065 source_path_map[fs->path()].push_back (fs);
4067 SeveralFileSources v;
4069 source_path_map.insert (make_pair (fs->path(), v));
4075 cerr << " fsources = " << total << endl;
4077 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4079 /* tell caller where we are */
4081 string old_path = i->first;
4083 callback (n, total, old_path);
4085 cerr << old_path << endl;
4089 switch (i->second.front()->type()) {
4090 case DataType::AUDIO:
4091 new_path = new_audio_source_path_for_embedded (old_path);
4094 case DataType::MIDI:
4095 /* XXX not implemented yet */
4099 if (new_path.empty()) {
4103 cerr << "Move " << old_path << " => " << new_path << endl;
4105 if (!copy_file (old_path, new_path)) {
4106 cerr << "failed !\n";
4110 /* make sure we stop looking in the external
4111 dir/folder. Remember, this is an all-or-nothing
4112 operations, it doesn't merge just some files.
4114 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4116 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4117 (*f)->set_path (new_path);
4122 save_state ("", false, false);
4128 bool accept_all_files (string const &, void *)
4134 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4136 /* 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.
4141 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4143 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4145 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4147 v.push_back (new_session_folder); /* full path */
4148 v.push_back (interchange_dir_name);
4149 v.push_back (new_session_path); /* just one directory/folder */
4150 v.push_back (typedir);
4151 v.push_back (Glib::path_get_basename (old_path));
4153 return Glib::build_filename (v);
4157 Session::save_as (SaveAs& saveas)
4159 vector<string> files;
4160 string current_folder = Glib::path_get_dirname (_path);
4161 string new_folder = legalize_for_path (saveas.new_name);
4162 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4163 int64_t total_bytes = 0;
4167 int32_t internal_file_cnt = 0;
4169 vector<string> do_not_copy_extensions;
4170 do_not_copy_extensions.push_back (statefile_suffix);
4171 do_not_copy_extensions.push_back (pending_suffix);
4172 do_not_copy_extensions.push_back (backup_suffix);
4173 do_not_copy_extensions.push_back (temp_suffix);
4174 do_not_copy_extensions.push_back (history_suffix);
4176 /* get total size */
4178 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4180 /* need to clear this because
4181 * find_files_matching_filter() is cumulative
4186 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4188 all += files.size();
4190 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4192 g_stat ((*i).c_str(), &gsb);
4193 total_bytes += gsb.st_size;
4197 /* save old values so we can switch back if we are not switching to the new session */
4199 string old_path = _path;
4200 string old_name = _name;
4201 string old_snapshot = _current_snapshot_name;
4202 string old_sd = _session_dir->root_path();
4203 vector<string> old_search_path[DataType::num_types];
4204 string old_config_search_path[DataType::num_types];
4206 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4207 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4208 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4209 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4211 /* switch session directory */
4213 (*_session_dir) = to_dir;
4215 /* create new tree */
4217 if (!_session_dir->create()) {
4218 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4223 /* copy all relevant files. Find each location in session_dirs,
4224 * and copy files from there to target.
4227 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4229 /* need to clear this because
4230 * find_files_matching_filter() is cumulative
4235 const size_t prefix_len = (*sd).path.size();
4237 /* Work just on the files within this session dir */
4239 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4241 /* add dir separator to protect against collisions with
4242 * track names (e.g. track named "audiofiles" or
4246 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4247 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4248 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4250 /* copy all the files. Handling is different for media files
4251 than others because of the *silly* subtree we have below the interchange
4252 folder. That really was a bad idea, but I'm not fixing it as part of
4253 implementing ::save_as().
4256 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4258 std::string from = *i;
4261 string filename = Glib::path_get_basename (from);
4262 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4263 if (filename == ".DS_STORE") {
4268 if (from.find (audiofile_dir_string) != string::npos) {
4270 /* audio file: only copy if asked */
4272 if (saveas.include_media && saveas.copy_media) {
4274 string to = make_new_media_path (*i, to_dir, new_folder);
4276 info << "media file copying from " << from << " to " << to << endmsg;
4278 if (!copy_file (from, to)) {
4279 throw Glib::FileError (Glib::FileError::IO_ERROR,
4280 string_compose(_("\ncopying \"%1\" failed !"), from));
4284 /* we found media files inside the session folder */
4286 internal_file_cnt++;
4288 } else if (from.find (midifile_dir_string) != string::npos) {
4290 /* midi file: always copy unless
4291 * creating an empty new session
4294 if (saveas.include_media) {
4296 string to = make_new_media_path (*i, to_dir, new_folder);
4298 info << "media file copying from " << from << " to " << to << endmsg;
4300 if (!copy_file (from, to)) {
4301 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4305 /* we found media files inside the session folder */
4307 internal_file_cnt++;
4309 } else if (from.find (analysis_dir_string) != string::npos) {
4311 /* make sure analysis dir exists in
4312 * new session folder, but we're not
4313 * copying analysis files here, see
4317 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4322 /* normal non-media file. Don't copy state, history, etc.
4325 bool do_copy = true;
4327 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4328 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4329 /* end of filename matches extension, do not copy file */
4335 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4336 /* don't copy peakfiles if
4337 * we're not copying media
4343 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4345 info << "attempting to make directory/folder " << to << endmsg;
4347 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4348 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4351 info << "attempting to copy " << from << " to " << to << endmsg;
4353 if (!copy_file (from, to)) {
4354 throw Glib::FileError (Glib::FileError::IO_ERROR,
4355 string_compose(_("\ncopying \"%1\" failed !"), from));
4360 /* measure file size even if we're not going to copy so that our Progress
4361 signals are correct, since we included these do-not-copy files
4362 in the computation of the total size and file count.
4366 g_stat (from.c_str(), &gsb);
4367 copied += gsb.st_size;
4370 double fraction = (double) copied / total_bytes;
4372 bool keep_going = true;
4374 if (saveas.copy_media) {
4376 /* no need or expectation of this if
4377 * media is not being copied, because
4378 * it will be fast(ish).
4381 /* tell someone "X percent, file M of N"; M is one-based */
4383 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4391 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4397 /* copy optional folders, if any */
4399 string old = plugins_dir ();
4400 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4401 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4402 copy_files (old, newdir);
4405 old = externals_dir ();
4406 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4407 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4408 copy_files (old, newdir);
4411 old = automation_dir ();
4412 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4413 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4414 copy_files (old, newdir);
4417 if (saveas.include_media) {
4419 if (saveas.copy_media) {
4420 #ifndef PLATFORM_WINDOWS
4421 /* There are problems with analysis files on
4422 * Windows, because they used a colon in their
4423 * names as late as 4.0. Colons are not legal
4424 * under Windows even if NTFS allows them.
4426 * This is a tricky problem to solve so for
4427 * just don't copy these files. They will be
4428 * regenerated as-needed anyway, subject to the
4429 * existing issue that the filenames will be
4430 * rejected by Windows, which is a separate
4431 * problem (though related).
4434 /* only needed if we are copying media, since the
4435 * analysis data refers to media data
4438 old = analysis_dir ();
4439 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4440 string newdir = Glib::build_filename (to_dir, "analysis");
4441 copy_files (old, newdir);
4443 #endif /* PLATFORM_WINDOWS */
4449 _current_snapshot_name = saveas.new_name;
4450 _name = saveas.new_name;
4452 if (saveas.include_media && !saveas.copy_media) {
4454 /* reset search paths of the new session (which we're pretending to be right now) to
4455 include the original session search path, so we can still find all audio.
4458 if (internal_file_cnt) {
4459 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4460 ensure_search_path_includes (*s, DataType::AUDIO);
4461 cerr << "be sure to include " << *s << " for audio" << endl;
4464 /* we do not do this for MIDI because we copy
4465 all MIDI files if saveas.include_media is
4471 bool was_dirty = dirty ();
4473 save_state ("", false, false, !saveas.include_media);
4474 save_default_options ();
4476 if (saveas.copy_media && saveas.copy_external) {
4477 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4478 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4482 saveas.final_session_folder_name = _path;
4484 store_recent_sessions (_name, _path);
4486 if (!saveas.switch_to) {
4488 /* switch back to the way things were */
4492 _current_snapshot_name = old_snapshot;
4494 (*_session_dir) = old_sd;
4500 if (internal_file_cnt) {
4501 /* reset these to their original values */
4502 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4503 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4508 /* prune session dirs, and update disk space statistics
4513 session_dirs.clear ();
4514 session_dirs.push_back (sp);
4515 refresh_disk_space ();
4517 /* ensure that all existing tracks reset their current capture source paths
4519 reset_write_sources (true, true);
4521 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4522 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4525 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4526 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4532 if (fs->within_session()) {
4533 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4534 fs->set_path (newpath);
4539 } catch (Glib::FileError& e) {
4541 saveas.failure_message = e.what();
4543 /* recursively remove all the directories */
4545 remove_directory (to_dir);
4553 saveas.failure_message = _("unknown reason");
4555 /* recursively remove all the directories */
4557 remove_directory (to_dir);