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"));
402 boost::shared_ptr<RouteList> rl = routes.reader();
403 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
404 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
405 if (trk && !trk->hidden()) {
406 trk->seek (_transport_frame, true);
412 Session::raid_path () const
414 Searchpath raid_search_path;
416 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
417 raid_search_path += (*i).path;
420 return raid_search_path.to_string ();
424 Session::setup_raid_path (string path)
433 session_dirs.clear ();
435 Searchpath search_path(path);
436 Searchpath sound_search_path;
437 Searchpath midi_search_path;
439 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
441 sp.blocks = 0; // not needed
442 session_dirs.push_back (sp);
444 SessionDirectory sdir(sp.path);
446 sound_search_path += sdir.sound_path ();
447 midi_search_path += sdir.midi_path ();
450 // reset the round-robin soundfile path thingie
451 last_rr_session_dir = session_dirs.begin();
455 Session::path_is_within_session (const std::string& path)
457 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
458 if (PBD::path_is_within (i->path, path)) {
466 Session::ensure_subdirs ()
470 dir = session_directory().peak_path();
472 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
473 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
477 dir = session_directory().sound_path();
479 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
480 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
484 dir = session_directory().midi_path();
486 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
487 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
491 dir = session_directory().dead_path();
493 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
494 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
498 dir = session_directory().export_path();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
505 dir = analysis_dir ();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
512 dir = plugins_dir ();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
519 dir = externals_dir ();
521 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
522 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
529 /** @param session_template directory containing session template, or empty.
530 * Caller must not hold process lock.
533 Session::create (const string& session_template, BusProfile* bus_profile)
535 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
536 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
540 if (ensure_subdirs ()) {
544 _writable = exists_and_writable (_path);
546 if (!session_template.empty()) {
547 std::string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
549 ifstream in(in_path.c_str());
552 /* no need to call legalize_for_path() since the string
553 * in session_template is already a legal path name
555 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
557 ofstream out(out_path.c_str());
563 if (!ARDOUR::Profile->get_trx()) {
564 /* Copy plugin state files from template to new session */
565 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
566 copy_recurse (template_plugins, plugins_dir ());
572 error << string_compose (_("Could not open %1 for writing session template"), out_path)
578 error << string_compose (_("Could not open session template %1 for reading"), in_path)
585 if (Profile->get_trx()) {
587 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
588 Remember that this is a brand new session. Sessions
589 loaded from saved state will get this range from the saved state.
592 set_session_range_location (0, 0);
594 /* Initial loop location, from absolute zero, length 10 seconds */
596 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
597 _locations->add (loc, true);
598 set_auto_loop_location (loc);
601 _state_of_the_state = Clean;
603 /* set up Master Out and Control Out if necessary */
608 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
610 // Waves Tracks: always create master bus for Tracks
611 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
612 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
616 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
617 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
620 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
621 r->input()->ensure_io (count, false, this);
622 r->output()->ensure_io (count, false, this);
628 /* prohibit auto-connect to master, because there isn't one */
629 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
633 add_routes (rl, false, false, false);
636 // Waves Tracks: Skip this. Always use autoconnection for Tracks
637 if (!ARDOUR::Profile->get_trx()) {
639 /* this allows the user to override settings with an environment variable.
642 if (no_auto_connect()) {
643 bus_profile->input_ac = AutoConnectOption (0);
644 bus_profile->output_ac = AutoConnectOption (0);
647 Config->set_input_auto_connect (bus_profile->input_ac);
648 Config->set_output_auto_connect (bus_profile->output_ac);
652 if (Config->get_use_monitor_bus() && bus_profile) {
653 add_monitor_section ();
660 Session::maybe_write_autosave()
662 if (dirty() && record_status() != Recording) {
663 save_state("", true);
668 Session::remove_pending_capture_state ()
670 std::string pending_state_file_path(_session_dir->root_path());
672 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
674 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
676 if (g_remove (pending_state_file_path.c_str()) != 0) {
677 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
678 pending_state_file_path, g_strerror (errno)) << endmsg;
682 /** Rename a state file.
683 * @param old_name Old snapshot name.
684 * @param new_name New snapshot name.
687 Session::rename_state (string old_name, string new_name)
689 if (old_name == _current_snapshot_name || old_name == _name) {
690 /* refuse to rename the current snapshot or the "main" one */
694 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
695 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
697 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
698 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
700 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
701 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
702 old_name, new_name, g_strerror(errno)) << endmsg;
706 /** Remove a state file.
707 * @param snapshot_name Snapshot name.
710 Session::remove_state (string snapshot_name)
712 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
713 // refuse to remove the current snapshot or the "main" one
717 std::string xml_path(_session_dir->root_path());
719 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
721 if (!create_backup_file (xml_path)) {
722 // don't remove it if a backup can't be made
723 // create_backup_file will log the error.
728 if (g_remove (xml_path.c_str()) != 0) {
729 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
730 xml_path, g_strerror (errno)) << endmsg;
734 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
736 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
739 std::string xml_path(_session_dir->root_path());
741 /* prevent concurrent saves from different threads */
743 Glib::Threads::Mutex::Lock lm (save_state_lock);
745 if (!_writable || (_state_of_the_state & CannotSave)) {
749 if (g_atomic_int_get(&_suspend_save)) {
753 _save_queued = false;
755 if (!_engine.connected ()) {
756 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
762 /* tell sources we're saving first, in case they write out to a new file
763 * which should be saved with the state rather than the old one */
764 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
766 i->second->session_saved();
767 } catch (Evoral::SMF::FileError& e) {
768 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
772 SessionSaveUnderway (); /* EMIT SIGNAL */
775 tree.set_root (&get_template());
777 tree.set_root (&get_state());
780 if (snapshot_name.empty()) {
781 snapshot_name = _current_snapshot_name;
782 } else if (switch_to_snapshot) {
783 _current_snapshot_name = snapshot_name;
788 /* proper save: use statefile_suffix (.ardour in English) */
790 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
792 /* make a backup copy of the old file */
794 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
795 // create_backup_file will log the error
801 /* pending save: use pending_suffix (.pending in English) */
802 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
805 std::string tmp_path(_session_dir->root_path());
806 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
808 cerr << "actually writing state to " << tmp_path << endl;
810 if (!tree.write (tmp_path)) {
811 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
812 if (g_remove (tmp_path.c_str()) != 0) {
813 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
814 tmp_path, g_strerror (errno)) << endmsg;
820 cerr << "renaming state to " << xml_path << endl;
822 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
823 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
824 tmp_path, xml_path, g_strerror(errno)) << endmsg;
825 if (g_remove (tmp_path.c_str()) != 0) {
826 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
827 tmp_path, g_strerror (errno)) << endmsg;
835 save_history (snapshot_name);
837 bool was_dirty = dirty();
839 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
842 DirtyChanged (); /* EMIT SIGNAL */
845 StateSaved (snapshot_name); /* EMIT SIGNAL */
852 Session::restore_state (string snapshot_name)
854 if (load_state (snapshot_name) == 0) {
855 set_state (*state_tree->root(), Stateful::loading_state_version);
862 Session::load_state (string snapshot_name)
867 state_was_pending = false;
869 /* check for leftover pending state from a crashed capture attempt */
871 std::string xmlpath(_session_dir->root_path());
872 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
874 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
876 /* there is pending state from a crashed capture attempt */
878 boost::optional<int> r = AskAboutPendingState();
879 if (r.get_value_or (1)) {
880 state_was_pending = true;
884 if (!state_was_pending) {
885 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
888 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
889 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
890 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
891 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
896 state_tree = new XMLTree;
900 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
902 if (!state_tree->read (xmlpath)) {
903 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
909 XMLNode& root (*state_tree->root());
911 if (root.name() != X_("Session")) {
912 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
918 const XMLProperty* prop;
920 if ((prop = root.property ("version")) == 0) {
921 /* no version implies very old version of Ardour */
922 Stateful::loading_state_version = 1000;
924 if (prop->value().find ('.') != string::npos) {
925 /* old school version format */
926 if (prop->value()[0] == '2') {
927 Stateful::loading_state_version = 2000;
929 Stateful::loading_state_version = 3000;
932 Stateful::loading_state_version = atoi (prop->value());
936 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
938 std::string backup_path(_session_dir->root_path());
939 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
940 backup_path = Glib::build_filename (backup_path, backup_filename);
942 // only create a backup for a given statefile version once
944 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
946 VersionMismatch (xmlpath, backup_path);
948 if (!copy_file (xmlpath, backup_path)) {;
958 Session::load_options (const XMLNode& node)
960 LocaleGuard lg (X_("C"));
961 config.set_variables (node);
966 Session::save_default_options ()
968 return config.save_state();
978 Session::get_template()
980 /* if we don't disable rec-enable, diskstreams
981 will believe they need to store their capture
982 sources in their state node.
985 disable_record (false);
991 Session::state (bool full_state)
993 XMLNode* node = new XMLNode("Session");
997 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
998 node->add_property("version", buf);
1000 /* store configuration settings */
1004 node->add_property ("name", _name);
1005 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1006 node->add_property ("sample-rate", buf);
1008 if (session_dirs.size() > 1) {
1012 vector<space_and_path>::iterator i = session_dirs.begin();
1013 vector<space_and_path>::iterator next;
1015 ++i; /* skip the first one */
1019 while (i != session_dirs.end()) {
1023 if (next != session_dirs.end()) {
1024 p += G_SEARCHPATH_SEPARATOR;
1033 child = node->add_child ("Path");
1034 child->add_content (p);
1038 /* save the ID counter */
1040 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1041 node->add_property ("id-counter", buf);
1043 /* save the event ID counter */
1045 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1046 node->add_property ("event-counter", buf);
1048 /* various options */
1050 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1051 if (!midi_port_nodes.empty()) {
1052 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1053 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1054 midi_port_stuff->add_child_nocopy (**n);
1056 node->add_child_nocopy (*midi_port_stuff);
1059 node->add_child_nocopy (config.get_variables ());
1061 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1063 child = node->add_child ("Sources");
1066 Glib::Threads::Mutex::Lock sl (source_lock);
1068 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1070 /* Don't save information about non-file Sources, or
1071 * about non-destructive file sources that are empty
1072 * and unused by any regions.
1075 boost::shared_ptr<FileSource> fs;
1077 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1079 if (!fs->destructive()) {
1080 if (fs->empty() && !fs->used()) {
1085 child->add_child_nocopy (siter->second->get_state());
1090 child = node->add_child ("Regions");
1093 Glib::Threads::Mutex::Lock rl (region_lock);
1094 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1095 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1096 boost::shared_ptr<Region> r = i->second;
1097 /* only store regions not attached to playlists */
1098 if (r->playlist() == 0) {
1099 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1100 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1102 child->add_child_nocopy (r->get_state ());
1107 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1109 if (!cassocs.empty()) {
1110 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1112 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1114 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1115 i->first->id().print (buf, sizeof (buf));
1116 can->add_property (X_("copy"), buf);
1117 i->second->id().print (buf, sizeof (buf));
1118 can->add_property (X_("original"), buf);
1119 ca->add_child_nocopy (*can);
1129 node->add_child_nocopy (_locations->get_state());
1132 Locations loc (*this);
1133 // for a template, just create a new Locations, populate it
1134 // with the default start and end, and get the state for that.
1135 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1136 range->set (max_framepos, 0);
1138 XMLNode& locations_state = loc.get_state();
1140 if (ARDOUR::Profile->get_trx() && _locations) {
1141 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1142 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1143 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1144 locations_state.add_child_nocopy ((*i)->get_state ());
1148 node->add_child_nocopy (locations_state);
1151 child = node->add_child ("Bundles");
1153 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1154 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1155 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1157 child->add_child_nocopy (b->get_state());
1162 child = node->add_child ("Routes");
1164 boost::shared_ptr<RouteList> r = routes.reader ();
1166 RoutePublicOrderSorter cmp;
1167 RouteList public_order (*r);
1168 public_order.sort (cmp);
1170 /* the sort should have put control outs first */
1173 assert (_monitor_out == public_order.front());
1176 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1177 if (!(*i)->is_auditioner()) {
1179 child->add_child_nocopy ((*i)->get_state());
1181 child->add_child_nocopy ((*i)->get_template());
1187 playlists->add_state (node, full_state);
1189 child = node->add_child ("RouteGroups");
1190 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1191 child->add_child_nocopy ((*i)->get_state());
1195 XMLNode* gain_child = node->add_child ("Click");
1196 gain_child->add_child_nocopy (_click_io->state (full_state));
1197 gain_child->add_child_nocopy (_click_gain->state (full_state));
1201 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1202 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1206 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1207 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1210 node->add_child_nocopy (_speakers->get_state());
1211 node->add_child_nocopy (_tempo_map->get_state());
1212 node->add_child_nocopy (get_control_protocol_state());
1215 node->add_child_copy (*_extra_xml);
1222 Session::get_control_protocol_state ()
1224 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1225 return cpm.get_state();
1229 Session::set_state (const XMLNode& node, int version)
1233 const XMLProperty* prop;
1236 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1238 if (node.name() != X_("Session")) {
1239 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1243 if ((prop = node.property ("name")) != 0) {
1244 _name = prop->value ();
1247 if ((prop = node.property (X_("sample-rate"))) != 0) {
1249 _nominal_frame_rate = atoi (prop->value());
1251 if (_nominal_frame_rate != _current_frame_rate) {
1252 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1253 if (r.get_value_or (0)) {
1259 setup_raid_path(_session_dir->root_path());
1261 if ((prop = node.property (X_("id-counter"))) != 0) {
1263 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1264 ID::init_counter (x);
1266 /* old sessions used a timebased counter, so fake
1267 the startup ID counter based on a standard
1272 ID::init_counter (now);
1275 if ((prop = node.property (X_("event-counter"))) != 0) {
1276 Evoral::init_event_id_counter (atoi (prop->value()));
1280 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1281 _midi_ports->set_midi_port_states (child->children());
1284 IO::disable_connecting ();
1286 Stateful::save_extra_xml (node);
1288 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1289 load_options (*child);
1290 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1291 load_options (*child);
1293 error << _("Session: XML state has no options section") << endmsg;
1296 if (version >= 3000) {
1297 if ((child = find_named_node (node, "Metadata")) == 0) {
1298 warning << _("Session: XML state has no metadata section") << endmsg;
1299 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1304 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1305 _speakers->set_state (*child, version);
1308 if ((child = find_named_node (node, "Sources")) == 0) {
1309 error << _("Session: XML state has no sources section") << endmsg;
1311 } else if (load_sources (*child)) {
1315 if ((child = find_named_node (node, "TempoMap")) == 0) {
1316 error << _("Session: XML state has no Tempo Map section") << endmsg;
1318 } else if (_tempo_map->set_state (*child, version)) {
1322 if ((child = find_named_node (node, "Locations")) == 0) {
1323 error << _("Session: XML state has no locations section") << endmsg;
1325 } else if (_locations->set_state (*child, version)) {
1329 locations_changed ();
1331 if (_session_range_location) {
1332 AudioFileSource::set_header_position_offset (_session_range_location->start());
1335 if ((child = find_named_node (node, "Regions")) == 0) {
1336 error << _("Session: XML state has no Regions section") << endmsg;
1338 } else if (load_regions (*child)) {
1342 if ((child = find_named_node (node, "Playlists")) == 0) {
1343 error << _("Session: XML state has no playlists section") << endmsg;
1345 } else if (playlists->load (*this, *child)) {
1349 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1351 } else if (playlists->load_unused (*this, *child)) {
1355 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1356 if (load_compounds (*child)) {
1361 if (version >= 3000) {
1362 if ((child = find_named_node (node, "Bundles")) == 0) {
1363 warning << _("Session: XML state has no bundles section") << endmsg;
1366 /* We can't load Bundles yet as they need to be able
1367 to convert from port names to Port objects, which can't happen until
1369 _bundle_xml_node = new XMLNode (*child);
1373 if (version < 3000) {
1374 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1375 error << _("Session: XML state has no diskstreams section") << endmsg;
1377 } else if (load_diskstreams_2X (*child, version)) {
1382 if ((child = find_named_node (node, "Routes")) == 0) {
1383 error << _("Session: XML state has no routes section") << endmsg;
1385 } else if (load_routes (*child, version)) {
1389 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1390 _diskstreams_2X.clear ();
1392 if (version >= 3000) {
1394 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1395 error << _("Session: XML state has no route groups section") << endmsg;
1397 } else if (load_route_groups (*child, version)) {
1401 } else if (version < 3000) {
1403 if ((child = find_named_node (node, "EditGroups")) == 0) {
1404 error << _("Session: XML state has no edit groups section") << endmsg;
1406 } else if (load_route_groups (*child, version)) {
1410 if ((child = find_named_node (node, "MixGroups")) == 0) {
1411 error << _("Session: XML state has no mix groups section") << endmsg;
1413 } else if (load_route_groups (*child, version)) {
1418 if ((child = find_named_node (node, "Click")) == 0) {
1419 warning << _("Session: XML state has no click section") << endmsg;
1420 } else if (_click_io) {
1421 setup_click_state (&node);
1424 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1425 ControlProtocolManager::instance().set_state (*child, version);
1428 update_route_record_state ();
1430 /* here beginneth the second phase ... */
1432 StateReady (); /* EMIT SIGNAL */
1445 Session::load_routes (const XMLNode& node, int version)
1448 XMLNodeConstIterator niter;
1449 RouteList new_routes;
1451 nlist = node.children();
1455 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1457 boost::shared_ptr<Route> route;
1458 if (version < 3000) {
1459 route = XMLRouteFactory_2X (**niter, version);
1461 route = XMLRouteFactory (**niter, version);
1465 error << _("Session: cannot create Route from XML description.") << endmsg;
1469 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1471 new_routes.push_back (route);
1474 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1476 add_routes (new_routes, false, false, false);
1478 BootMessage (_("Finished adding tracks/busses"));
1483 boost::shared_ptr<Route>
1484 Session::XMLRouteFactory (const XMLNode& node, int version)
1486 boost::shared_ptr<Route> ret;
1488 if (node.name() != "Route") {
1492 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1494 DataType type = DataType::AUDIO;
1495 const XMLProperty* prop = node.property("default-type");
1498 type = DataType (prop->value());
1501 assert (type != DataType::NIL);
1505 boost::shared_ptr<Track> track;
1507 if (type == DataType::AUDIO) {
1508 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1510 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1513 if (track->init()) {
1517 if (track->set_state (node, version)) {
1521 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1522 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1527 enum Route::Flag flags = Route::Flag(0);
1528 const XMLProperty* prop = node.property("flags");
1530 flags = Route::Flag (string_2_enum (prop->value(), flags));
1533 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1535 if (r->init () == 0 && r->set_state (node, version) == 0) {
1536 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1537 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1546 boost::shared_ptr<Route>
1547 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1549 boost::shared_ptr<Route> ret;
1551 if (node.name() != "Route") {
1555 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1557 ds_prop = node.property (X_("diskstream"));
1560 DataType type = DataType::AUDIO;
1561 const XMLProperty* prop = node.property("default-type");
1564 type = DataType (prop->value());
1567 assert (type != DataType::NIL);
1571 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1572 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1576 if (i == _diskstreams_2X.end()) {
1577 error << _("Could not find diskstream for route") << endmsg;
1578 return boost::shared_ptr<Route> ();
1581 boost::shared_ptr<Track> track;
1583 if (type == DataType::AUDIO) {
1584 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1586 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1589 if (track->init()) {
1593 if (track->set_state (node, version)) {
1597 track->set_diskstream (*i);
1599 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1600 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1605 enum Route::Flag flags = Route::Flag(0);
1606 const XMLProperty* prop = node.property("flags");
1608 flags = Route::Flag (string_2_enum (prop->value(), flags));
1611 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1613 if (r->init () == 0 && r->set_state (node, version) == 0) {
1614 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1615 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1625 Session::load_regions (const XMLNode& node)
1628 XMLNodeConstIterator niter;
1629 boost::shared_ptr<Region> region;
1631 nlist = node.children();
1635 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1636 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1637 error << _("Session: cannot create Region from XML description.");
1638 const XMLProperty *name = (**niter).property("name");
1641 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1652 Session::load_compounds (const XMLNode& node)
1654 XMLNodeList calist = node.children();
1655 XMLNodeConstIterator caiter;
1656 XMLProperty *caprop;
1658 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1659 XMLNode* ca = *caiter;
1663 if ((caprop = ca->property (X_("original"))) == 0) {
1666 orig_id = caprop->value();
1668 if ((caprop = ca->property (X_("copy"))) == 0) {
1671 copy_id = caprop->value();
1673 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1674 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1676 if (!orig || !copy) {
1677 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1683 RegionFactory::add_compound_association (orig, copy);
1690 Session::load_nested_sources (const XMLNode& node)
1693 XMLNodeConstIterator niter;
1695 nlist = node.children();
1697 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1698 if ((*niter)->name() == "Source") {
1700 /* it may already exist, so don't recreate it unnecessarily
1703 XMLProperty* prop = (*niter)->property (X_("id"));
1705 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1709 ID source_id (prop->value());
1711 if (!source_by_id (source_id)) {
1714 SourceFactory::create (*this, **niter, true);
1716 catch (failed_constructor& err) {
1717 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1724 boost::shared_ptr<Region>
1725 Session::XMLRegionFactory (const XMLNode& node, bool full)
1727 const XMLProperty* type = node.property("type");
1731 const XMLNodeList& nlist = node.children();
1733 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1734 XMLNode *child = (*niter);
1735 if (child->name() == "NestedSource") {
1736 load_nested_sources (*child);
1740 if (!type || type->value() == "audio") {
1741 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1742 } else if (type->value() == "midi") {
1743 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1746 } catch (failed_constructor& err) {
1747 return boost::shared_ptr<Region> ();
1750 return boost::shared_ptr<Region> ();
1753 boost::shared_ptr<AudioRegion>
1754 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1756 const XMLProperty* prop;
1757 boost::shared_ptr<Source> source;
1758 boost::shared_ptr<AudioSource> as;
1760 SourceList master_sources;
1761 uint32_t nchans = 1;
1764 if (node.name() != X_("Region")) {
1765 return boost::shared_ptr<AudioRegion>();
1768 if ((prop = node.property (X_("channels"))) != 0) {
1769 nchans = atoi (prop->value().c_str());
1772 if ((prop = node.property ("name")) == 0) {
1773 cerr << "no name for this region\n";
1777 if ((prop = node.property (X_("source-0"))) == 0) {
1778 if ((prop = node.property ("source")) == 0) {
1779 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1780 return boost::shared_ptr<AudioRegion>();
1784 PBD::ID s_id (prop->value());
1786 if ((source = source_by_id (s_id)) == 0) {
1787 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1788 return boost::shared_ptr<AudioRegion>();
1791 as = boost::dynamic_pointer_cast<AudioSource>(source);
1793 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1794 return boost::shared_ptr<AudioRegion>();
1797 sources.push_back (as);
1799 /* pickup other channels */
1801 for (uint32_t n=1; n < nchans; ++n) {
1802 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1803 if ((prop = node.property (buf)) != 0) {
1805 PBD::ID id2 (prop->value());
1807 if ((source = source_by_id (id2)) == 0) {
1808 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1809 return boost::shared_ptr<AudioRegion>();
1812 as = boost::dynamic_pointer_cast<AudioSource>(source);
1814 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1815 return boost::shared_ptr<AudioRegion>();
1817 sources.push_back (as);
1821 for (uint32_t n = 0; n < nchans; ++n) {
1822 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1823 if ((prop = node.property (buf)) != 0) {
1825 PBD::ID id2 (prop->value());
1827 if ((source = source_by_id (id2)) == 0) {
1828 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1829 return boost::shared_ptr<AudioRegion>();
1832 as = boost::dynamic_pointer_cast<AudioSource>(source);
1834 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1835 return boost::shared_ptr<AudioRegion>();
1837 master_sources.push_back (as);
1842 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1844 /* a final detail: this is the one and only place that we know how long missing files are */
1846 if (region->whole_file()) {
1847 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1848 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1850 sfp->set_length (region->length());
1855 if (!master_sources.empty()) {
1856 if (master_sources.size() != nchans) {
1857 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1859 region->set_master_sources (master_sources);
1867 catch (failed_constructor& err) {
1868 return boost::shared_ptr<AudioRegion>();
1872 boost::shared_ptr<MidiRegion>
1873 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1875 const XMLProperty* prop;
1876 boost::shared_ptr<Source> source;
1877 boost::shared_ptr<MidiSource> ms;
1880 if (node.name() != X_("Region")) {
1881 return boost::shared_ptr<MidiRegion>();
1884 if ((prop = node.property ("name")) == 0) {
1885 cerr << "no name for this region\n";
1889 if ((prop = node.property (X_("source-0"))) == 0) {
1890 if ((prop = node.property ("source")) == 0) {
1891 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1892 return boost::shared_ptr<MidiRegion>();
1896 PBD::ID s_id (prop->value());
1898 if ((source = source_by_id (s_id)) == 0) {
1899 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1900 return boost::shared_ptr<MidiRegion>();
1903 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1905 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1906 return boost::shared_ptr<MidiRegion>();
1909 sources.push_back (ms);
1912 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1913 /* a final detail: this is the one and only place that we know how long missing files are */
1915 if (region->whole_file()) {
1916 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1917 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1919 sfp->set_length (region->length());
1927 catch (failed_constructor& err) {
1928 return boost::shared_ptr<MidiRegion>();
1933 Session::get_sources_as_xml ()
1936 XMLNode* node = new XMLNode (X_("Sources"));
1937 Glib::Threads::Mutex::Lock lm (source_lock);
1939 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1940 node->add_child_nocopy (i->second->get_state());
1947 Session::reset_write_sources (bool mark_write_complete, bool force)
1949 boost::shared_ptr<RouteList> rl = routes.reader();
1950 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1951 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1953 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1954 tr->reset_write_sources(mark_write_complete, force);
1955 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1961 Session::load_sources (const XMLNode& node)
1964 XMLNodeConstIterator niter;
1965 boost::shared_ptr<Source> source; /* don't need this but it stops some
1966 * versions of gcc complaining about
1967 * discarded return values.
1970 nlist = node.children();
1974 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1977 if ((source = XMLSourceFactory (**niter)) == 0) {
1978 error << _("Session: cannot create Source from XML description.") << endmsg;
1981 } catch (MissingSource& err) {
1985 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1986 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1987 PROGRAM_NAME) << endmsg;
1991 if (!no_questions_about_missing_files) {
1992 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1997 switch (user_choice) {
1999 /* user added a new search location, so try again */
2004 /* user asked to quit the entire session load
2009 no_questions_about_missing_files = true;
2013 no_questions_about_missing_files = true;
2020 case DataType::AUDIO:
2021 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2024 case DataType::MIDI:
2025 /* The MIDI file is actually missing so
2026 * just create a new one in the same
2027 * location. Do not announce its
2031 if (!Glib::path_is_absolute (err.path)) {
2032 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2034 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2039 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2040 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2041 /* reset ID to match the missing one */
2042 source->set_id (**niter);
2043 /* Now we can announce it */
2044 SourceFactory::SourceCreated (source);
2055 boost::shared_ptr<Source>
2056 Session::XMLSourceFactory (const XMLNode& node)
2058 if (node.name() != "Source") {
2059 return boost::shared_ptr<Source>();
2063 /* note: do peak building in another thread when loading session state */
2064 return SourceFactory::create (*this, node, true);
2067 catch (failed_constructor& err) {
2068 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2069 return boost::shared_ptr<Source>();
2074 Session::save_template (string template_name)
2076 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2080 bool absolute_path = Glib::path_is_absolute (template_name);
2082 /* directory to put the template in */
2083 std::string template_dir_path;
2085 if (!absolute_path) {
2086 std::string user_template_dir(user_template_directory());
2088 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2089 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2090 user_template_dir, g_strerror (errno)) << endmsg;
2094 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2096 template_dir_path = template_name;
2099 if (!ARDOUR::Profile->get_trx()) {
2100 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2101 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2102 template_dir_path) << endmsg;
2106 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2107 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2108 template_dir_path, g_strerror (errno)) << endmsg;
2114 std::string template_file_path;
2116 if (ARDOUR::Profile->get_trx()) {
2117 template_file_path = template_name;
2119 if (absolute_path) {
2120 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2122 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2126 SessionSaveUnderway (); /* EMIT SIGNAL */
2130 tree.set_root (&get_template());
2131 if (!tree.write (template_file_path)) {
2132 error << _("template not saved") << endmsg;
2136 if (!ARDOUR::Profile->get_trx()) {
2137 /* copy plugin state directory */
2139 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2141 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2142 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2143 template_plugin_state_path, g_strerror (errno)) << endmsg;
2146 copy_files (plugins_dir(), template_plugin_state_path);
2149 store_recent_templates (template_file_path);
2155 Session::refresh_disk_space ()
2157 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2159 Glib::Threads::Mutex::Lock lm (space_lock);
2161 /* get freespace on every FS that is part of the session path */
2163 _total_free_4k_blocks = 0;
2164 _total_free_4k_blocks_uncertain = false;
2166 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2168 struct statfs statfsbuf;
2169 statfs (i->path.c_str(), &statfsbuf);
2171 double const scale = statfsbuf.f_bsize / 4096.0;
2173 /* See if this filesystem is read-only */
2174 struct statvfs statvfsbuf;
2175 statvfs (i->path.c_str(), &statvfsbuf);
2177 /* f_bavail can be 0 if it is undefined for whatever
2178 filesystem we are looking at; Samba shares mounted
2179 via GVFS are an example of this.
2181 if (statfsbuf.f_bavail == 0) {
2182 /* block count unknown */
2184 i->blocks_unknown = true;
2185 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2186 /* read-only filesystem */
2188 i->blocks_unknown = false;
2190 /* read/write filesystem with known space */
2191 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2192 i->blocks_unknown = false;
2195 _total_free_4k_blocks += i->blocks;
2196 if (i->blocks_unknown) {
2197 _total_free_4k_blocks_uncertain = true;
2200 #elif defined PLATFORM_WINDOWS
2201 vector<string> scanned_volumes;
2202 vector<string>::iterator j;
2203 vector<space_and_path>::iterator i;
2204 DWORD nSectorsPerCluster, nBytesPerSector,
2205 nFreeClusters, nTotalClusters;
2209 _total_free_4k_blocks = 0;
2211 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2212 strncpy (disk_drive, (*i).path.c_str(), 3);
2216 volume_found = false;
2217 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2219 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2220 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2221 i->blocks = (uint32_t)(nFreeBytes / 4096);
2223 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2224 if (0 == j->compare(disk_drive)) {
2225 volume_found = true;
2230 if (!volume_found) {
2231 scanned_volumes.push_back(disk_drive);
2232 _total_free_4k_blocks += i->blocks;
2237 if (0 == _total_free_4k_blocks) {
2238 strncpy (disk_drive, path().c_str(), 3);
2241 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2243 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2244 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2245 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2252 Session::get_best_session_directory_for_new_audio ()
2254 vector<space_and_path>::iterator i;
2255 string result = _session_dir->root_path();
2257 /* handle common case without system calls */
2259 if (session_dirs.size() == 1) {
2263 /* OK, here's the algorithm we're following here:
2265 We want to select which directory to use for
2266 the next file source to be created. Ideally,
2267 we'd like to use a round-robin process so as to
2268 get maximum performance benefits from splitting
2269 the files across multiple disks.
2271 However, in situations without much diskspace, an
2272 RR approach may end up filling up a filesystem
2273 with new files while others still have space.
2274 Its therefore important to pay some attention to
2275 the freespace in the filesystem holding each
2276 directory as well. However, if we did that by
2277 itself, we'd keep creating new files in the file
2278 system with the most space until it was as full
2279 as all others, thus negating any performance
2280 benefits of this RAID-1 like approach.
2282 So, we use a user-configurable space threshold. If
2283 there are at least 2 filesystems with more than this
2284 much space available, we use RR selection between them.
2285 If not, then we pick the filesystem with the most space.
2287 This gets a good balance between the two
2291 refresh_disk_space ();
2293 int free_enough = 0;
2295 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2296 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2301 if (free_enough >= 2) {
2302 /* use RR selection process, ensuring that the one
2306 i = last_rr_session_dir;
2309 if (++i == session_dirs.end()) {
2310 i = session_dirs.begin();
2313 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2314 SessionDirectory sdir(i->path);
2315 if (sdir.create ()) {
2317 last_rr_session_dir = i;
2322 } while (i != last_rr_session_dir);
2326 /* pick FS with the most freespace (and that
2327 seems to actually work ...)
2330 vector<space_and_path> sorted;
2331 space_and_path_ascending_cmp cmp;
2333 sorted = session_dirs;
2334 sort (sorted.begin(), sorted.end(), cmp);
2336 for (i = sorted.begin(); i != sorted.end(); ++i) {
2337 SessionDirectory sdir(i->path);
2338 if (sdir.create ()) {
2340 last_rr_session_dir = i;
2350 Session::automation_dir () const
2352 return Glib::build_filename (_path, automation_dir_name);
2356 Session::analysis_dir () const
2358 return Glib::build_filename (_path, analysis_dir_name);
2362 Session::plugins_dir () const
2364 return Glib::build_filename (_path, plugins_dir_name);
2368 Session::externals_dir () const
2370 return Glib::build_filename (_path, externals_dir_name);
2374 Session::load_bundles (XMLNode const & node)
2376 XMLNodeList nlist = node.children();
2377 XMLNodeConstIterator niter;
2381 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2382 if ((*niter)->name() == "InputBundle") {
2383 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2384 } else if ((*niter)->name() == "OutputBundle") {
2385 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2387 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2396 Session::load_route_groups (const XMLNode& node, int version)
2398 XMLNodeList nlist = node.children();
2399 XMLNodeConstIterator niter;
2403 if (version >= 3000) {
2405 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2406 if ((*niter)->name() == "RouteGroup") {
2407 RouteGroup* rg = new RouteGroup (*this, "");
2408 add_route_group (rg);
2409 rg->set_state (**niter, version);
2413 } else if (version < 3000) {
2415 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2416 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2417 RouteGroup* rg = new RouteGroup (*this, "");
2418 add_route_group (rg);
2419 rg->set_state (**niter, version);
2428 state_file_filter (const string &str, void* /*arg*/)
2430 return (str.length() > strlen(statefile_suffix) &&
2431 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2435 remove_end(string state)
2437 string statename(state);
2439 string::size_type start,end;
2440 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2441 statename = statename.substr (start+1);
2444 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2445 end = statename.length();
2448 return string(statename.substr (0, end));
2452 Session::possible_states (string path)
2454 vector<string> states;
2455 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2457 transform(states.begin(), states.end(), states.begin(), remove_end);
2459 sort (states.begin(), states.end());
2465 Session::possible_states () const
2467 return possible_states(_path);
2471 Session::add_route_group (RouteGroup* g)
2473 _route_groups.push_back (g);
2474 route_group_added (g); /* EMIT SIGNAL */
2476 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2477 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2478 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2484 Session::remove_route_group (RouteGroup& rg)
2486 list<RouteGroup*>::iterator i;
2488 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2489 _route_groups.erase (i);
2492 route_group_removed (); /* EMIT SIGNAL */
2496 /** Set a new order for our route groups, without adding or removing any.
2497 * @param groups Route group list in the new order.
2500 Session::reorder_route_groups (list<RouteGroup*> groups)
2502 _route_groups = groups;
2504 route_groups_reordered (); /* EMIT SIGNAL */
2510 Session::route_group_by_name (string name)
2512 list<RouteGroup *>::iterator i;
2514 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2515 if ((*i)->name() == name) {
2523 Session::all_route_group() const
2525 return *_all_route_group;
2529 Session::add_commands (vector<Command*> const & cmds)
2531 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2537 Session::begin_reversible_command (const string& name)
2539 begin_reversible_command (g_quark_from_string (name.c_str ()));
2542 /** Begin a reversible command using a GQuark to identify it.
2543 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2544 * but there must be as many begin...()s as there are commit...()s.
2547 Session::begin_reversible_command (GQuark q)
2549 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2550 to hold all the commands that are committed. This keeps the order of
2551 commands correct in the history.
2554 if (_current_trans == 0) {
2555 /* start a new transaction */
2556 assert (_current_trans_quarks.empty ());
2557 _current_trans = new UndoTransaction();
2558 _current_trans->set_name (g_quark_to_string (q));
2561 _current_trans_quarks.push_front (q);
2565 Session::abort_reversible_command ()
2567 if (_current_trans != 0) {
2568 _current_trans->clear();
2569 delete _current_trans;
2571 _current_trans_quarks.clear();
2576 Session::commit_reversible_command (Command *cmd)
2578 assert (_current_trans);
2579 assert (!_current_trans_quarks.empty ());
2584 _current_trans->add_command (cmd);
2587 _current_trans_quarks.pop_front ();
2589 if (!_current_trans_quarks.empty ()) {
2590 /* the transaction we're committing is not the top-level one */
2594 if (_current_trans->empty()) {
2595 /* no commands were added to the transaction, so just get rid of it */
2596 delete _current_trans;
2601 gettimeofday (&now, 0);
2602 _current_trans->set_timestamp (now);
2604 _history.add (_current_trans);
2609 accept_all_audio_files (const string& path, void* /*arg*/)
2611 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2615 if (!AudioFileSource::safe_audio_file_extension (path)) {
2623 accept_all_midi_files (const string& path, void* /*arg*/)
2625 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2629 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2630 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2631 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2635 accept_all_state_files (const string& path, void* /*arg*/)
2637 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2641 std::string const statefile_ext (statefile_suffix);
2642 if (path.length() >= statefile_ext.length()) {
2643 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2650 Session::find_all_sources (string path, set<string>& result)
2655 if (!tree.read (path)) {
2659 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2664 XMLNodeConstIterator niter;
2666 nlist = node->children();
2670 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2674 if ((prop = (*niter)->property (X_("type"))) == 0) {
2678 DataType type (prop->value());
2680 if ((prop = (*niter)->property (X_("name"))) == 0) {
2684 if (Glib::path_is_absolute (prop->value())) {
2685 /* external file, ignore */
2693 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2694 result.insert (found_path);
2702 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2704 vector<string> state_files;
2706 string this_snapshot_path;
2712 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2713 ripped = ripped.substr (0, ripped.length() - 1);
2716 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2718 if (state_files.empty()) {
2723 this_snapshot_path = _path;
2724 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2725 this_snapshot_path += statefile_suffix;
2727 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2729 if (exclude_this_snapshot && *i == this_snapshot_path) {
2733 if (find_all_sources (*i, result) < 0) {
2741 struct RegionCounter {
2742 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2743 AudioSourceList::iterator iter;
2744 boost::shared_ptr<Region> region;
2747 RegionCounter() : count (0) {}
2751 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2753 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2754 return r.get_value_or (1);
2758 Session::cleanup_regions ()
2760 bool removed = false;
2761 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2763 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2765 uint32_t used = playlists->region_use_count (i->second);
2767 if (used == 0 && !i->second->automatic ()) {
2769 RegionFactory::map_remove (i->second);
2774 // re-check to remove parent references of compound regions
2775 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2776 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2779 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2780 if (0 == playlists->region_use_count (i->second)) {
2781 RegionFactory::map_remove (i->second);
2786 /* dump the history list */
2793 Session::cleanup_sources (CleanupReport& rep)
2795 // FIXME: needs adaptation to midi
2797 vector<boost::shared_ptr<Source> > dead_sources;
2800 vector<string> candidates;
2801 vector<string> unused;
2802 set<string> all_sources;
2811 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2813 /* consider deleting all unused playlists */
2815 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2820 /* sync the "all regions" property of each playlist with its current state
2823 playlists->sync_all_regions_with_regions ();
2825 /* find all un-used sources */
2830 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2832 SourceMap::iterator tmp;
2837 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2841 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2842 dead_sources.push_back (i->second);
2843 i->second->drop_references ();
2849 /* build a list of all the possible audio directories for the session */
2851 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2852 SessionDirectory sdir ((*i).path);
2853 asp += sdir.sound_path();
2855 audio_path += asp.to_string();
2858 /* build a list of all the possible midi directories for the session */
2860 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2861 SessionDirectory sdir ((*i).path);
2862 msp += sdir.midi_path();
2864 midi_path += msp.to_string();
2866 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2867 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2869 /* find all sources, but don't use this snapshot because the
2870 state file on disk still references sources we may have already
2874 find_all_sources_across_snapshots (all_sources, true);
2876 /* add our current source list
2879 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2880 boost::shared_ptr<FileSource> fs;
2881 SourceMap::iterator tmp = i;
2884 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2886 if (!fs->is_stub()) {
2888 if (playlists->source_use_count (fs) != 0) {
2889 all_sources.insert (fs->path());
2892 /* we might not remove this source from disk, because it may be used
2893 by other snapshots, but its not being used in this version
2894 so lets get rid of it now, along with any representative regions
2898 RegionFactory::remove_regions_using_source (i->second);
2901 // also remove source from all_sources
2903 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2904 spath = Glib::path_get_basename (*j);
2905 if ( spath == i->second->name () ) {
2906 all_sources.erase (j);
2917 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2922 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2924 tmppath1 = canonical_path (spath);
2925 tmppath2 = canonical_path ((*i));
2927 if (tmppath1 == tmppath2) {
2934 unused.push_back (spath);
2938 /* now try to move all unused files into the "dead" directory(ies) */
2940 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2941 struct stat statbuf;
2945 /* don't move the file across filesystems, just
2946 stick it in the `dead_dir_name' directory
2947 on whichever filesystem it was already on.
2950 if ((*x).find ("/sounds/") != string::npos) {
2952 /* old school, go up 1 level */
2954 newpath = Glib::path_get_dirname (*x); // "sounds"
2955 newpath = Glib::path_get_dirname (newpath); // "session-name"
2959 /* new school, go up 4 levels */
2961 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2962 newpath = Glib::path_get_dirname (newpath); // "session-name"
2963 newpath = Glib::path_get_dirname (newpath); // "interchange"
2964 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2967 newpath = Glib::build_filename (newpath, dead_dir_name);
2969 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2970 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2974 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2976 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2978 /* the new path already exists, try versioning */
2980 char buf[PATH_MAX+1];
2984 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2987 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2988 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2992 if (version == 999) {
2993 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2997 newpath = newpath_v;
3002 /* it doesn't exist, or we can't read it or something */
3006 stat ((*x).c_str(), &statbuf);
3008 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3009 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3010 (*x), newpath, strerror (errno))
3015 /* see if there an easy to find peakfile for this file, and remove it.
3018 string base = basename_nosuffix (*x);
3019 base += "%A"; /* this is what we add for the channel suffix of all native files,
3020 or for the first channel of embedded files. it will miss
3021 some peakfiles for other channels
3023 string peakpath = peak_path (base);
3025 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3026 if (::g_unlink (peakpath.c_str()) != 0) {
3027 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3028 peakpath, _path, strerror (errno))
3030 /* try to back out */
3031 ::rename (newpath.c_str(), _path.c_str());
3036 rep.paths.push_back (*x);
3037 rep.space += statbuf.st_size;
3040 /* dump the history list */
3044 /* save state so we don't end up a session file
3045 referring to non-existent sources.
3052 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3058 Session::cleanup_trash_sources (CleanupReport& rep)
3060 // FIXME: needs adaptation for MIDI
3062 vector<space_and_path>::iterator i;
3068 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3070 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3072 clear_directory (dead_dir, &rep.space, &rep.paths);
3079 Session::set_dirty ()
3081 /* never mark session dirty during loading */
3083 if (_state_of_the_state & Loading) {
3087 bool was_dirty = dirty();
3089 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3093 DirtyChanged(); /* EMIT SIGNAL */
3099 Session::set_clean ()
3101 bool was_dirty = dirty();
3103 _state_of_the_state = Clean;
3107 DirtyChanged(); /* EMIT SIGNAL */
3112 Session::set_deletion_in_progress ()
3114 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3118 Session::clear_deletion_in_progress ()
3120 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3124 Session::add_controllable (boost::shared_ptr<Controllable> c)
3126 /* this adds a controllable to the list managed by the Session.
3127 this is a subset of those managed by the Controllable class
3128 itself, and represents the only ones whose state will be saved
3129 as part of the session.
3132 Glib::Threads::Mutex::Lock lm (controllables_lock);
3133 controllables.insert (c);
3136 struct null_deleter { void operator()(void const *) const {} };
3139 Session::remove_controllable (Controllable* c)
3141 if (_state_of_the_state & Deletion) {
3145 Glib::Threads::Mutex::Lock lm (controllables_lock);
3147 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3149 if (x != controllables.end()) {
3150 controllables.erase (x);
3154 boost::shared_ptr<Controllable>
3155 Session::controllable_by_id (const PBD::ID& id)
3157 Glib::Threads::Mutex::Lock lm (controllables_lock);
3159 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3160 if ((*i)->id() == id) {
3165 return boost::shared_ptr<Controllable>();
3168 boost::shared_ptr<Controllable>
3169 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3171 boost::shared_ptr<Controllable> c;
3172 boost::shared_ptr<Route> r;
3174 switch (desc.top_level_type()) {
3175 case ControllableDescriptor::NamedRoute:
3177 std::string str = desc.top_level_name();
3178 if (str == "Master" || str == "master") {
3180 } else if (str == "control" || str == "listen") {
3183 r = route_by_name (desc.top_level_name());
3188 case ControllableDescriptor::RemoteControlID:
3189 r = route_by_remote_id (desc.rid());
3197 switch (desc.subtype()) {
3198 case ControllableDescriptor::Gain:
3199 c = r->gain_control ();
3202 case ControllableDescriptor::Trim:
3203 c = r->trim()->gain_control ();
3206 case ControllableDescriptor::Solo:
3207 c = r->solo_control();
3210 case ControllableDescriptor::Mute:
3211 c = r->mute_control();
3214 case ControllableDescriptor::Recenable:
3216 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3219 c = t->rec_enable_control ();
3224 case ControllableDescriptor::PanDirection:
3226 c = r->pannable()->pan_azimuth_control;
3230 case ControllableDescriptor::PanWidth:
3232 c = r->pannable()->pan_width_control;
3236 case ControllableDescriptor::PanElevation:
3238 c = r->pannable()->pan_elevation_control;
3242 case ControllableDescriptor::Balance:
3243 /* XXX simple pan control */
3246 case ControllableDescriptor::PluginParameter:
3248 uint32_t plugin = desc.target (0);
3249 uint32_t parameter_index = desc.target (1);
3251 /* revert to zero based counting */
3257 if (parameter_index > 0) {
3261 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3264 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3265 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3270 case ControllableDescriptor::SendGain:
3272 uint32_t send = desc.target (0);
3274 /* revert to zero-based counting */
3280 boost::shared_ptr<Processor> p = r->nth_send (send);
3283 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3284 boost::shared_ptr<Amp> a = s->amp();
3287 c = s->amp()->gain_control();
3294 /* relax and return a null pointer */
3302 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3305 Stateful::add_instant_xml (node, _path);
3308 if (write_to_config) {
3309 Config->add_instant_xml (node);
3314 Session::instant_xml (const string& node_name)
3316 return Stateful::instant_xml (node_name, _path);
3320 Session::save_history (string snapshot_name)
3328 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3329 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3333 if (snapshot_name.empty()) {
3334 snapshot_name = _current_snapshot_name;
3337 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3338 const string backup_filename = history_filename + backup_suffix;
3339 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3340 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3342 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3343 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3344 error << _("could not backup old history file, current history not saved") << endmsg;
3349 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3351 if (!tree.write (xml_path))
3353 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3355 if (g_remove (xml_path.c_str()) != 0) {
3356 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3357 xml_path, g_strerror (errno)) << endmsg;
3359 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3360 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3361 backup_path, g_strerror (errno)) << endmsg;
3371 Session::restore_history (string snapshot_name)
3375 if (snapshot_name.empty()) {
3376 snapshot_name = _current_snapshot_name;
3379 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3380 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3382 info << "Loading history from " << xml_path << endmsg;
3384 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3385 info << string_compose (_("%1: no history file \"%2\" for this session."),
3386 _name, xml_path) << endmsg;
3390 if (!tree.read (xml_path)) {
3391 error << string_compose (_("Could not understand session history file \"%1\""),
3392 xml_path) << endmsg;
3399 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3402 UndoTransaction* ut = new UndoTransaction ();
3405 ut->set_name(t->property("name")->value());
3406 stringstream ss(t->property("tv-sec")->value());
3408 ss.str(t->property("tv-usec")->value());
3410 ut->set_timestamp(tv);
3412 for (XMLNodeConstIterator child_it = t->children().begin();
3413 child_it != t->children().end(); child_it++)
3415 XMLNode *n = *child_it;
3418 if (n->name() == "MementoCommand" ||
3419 n->name() == "MementoUndoCommand" ||
3420 n->name() == "MementoRedoCommand") {
3422 if ((c = memento_command_factory(n))) {
3426 } else if (n->name() == "NoteDiffCommand") {
3427 PBD::ID id (n->property("midi-source")->value());
3428 boost::shared_ptr<MidiSource> midi_source =
3429 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3431 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3433 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3436 } else if (n->name() == "SysExDiffCommand") {
3438 PBD::ID id (n->property("midi-source")->value());
3439 boost::shared_ptr<MidiSource> midi_source =
3440 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3442 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3444 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3447 } else if (n->name() == "PatchChangeDiffCommand") {
3449 PBD::ID id (n->property("midi-source")->value());
3450 boost::shared_ptr<MidiSource> midi_source =
3451 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3453 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3455 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3458 } else if (n->name() == "StatefulDiffCommand") {
3459 if ((c = stateful_diff_command_factory (n))) {
3460 ut->add_command (c);
3463 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3474 Session::config_changed (std::string p, bool ours)
3480 if (p == "seamless-loop") {
3482 } else if (p == "rf-speed") {
3484 } else if (p == "auto-loop") {
3486 } else if (p == "auto-input") {
3488 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3489 /* auto-input only makes a difference if we're rolling */
3490 set_track_monitor_input_status (!config.get_auto_input());
3493 } else if (p == "punch-in") {
3497 if ((location = _locations->auto_punch_location()) != 0) {
3499 if (config.get_punch_in ()) {
3500 replace_event (SessionEvent::PunchIn, location->start());
3502 remove_event (location->start(), SessionEvent::PunchIn);
3506 } else if (p == "punch-out") {
3510 if ((location = _locations->auto_punch_location()) != 0) {
3512 if (config.get_punch_out()) {
3513 replace_event (SessionEvent::PunchOut, location->end());
3515 clear_events (SessionEvent::PunchOut);
3519 } else if (p == "edit-mode") {
3521 Glib::Threads::Mutex::Lock lm (playlists->lock);
3523 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3524 (*i)->set_edit_mode (Config->get_edit_mode ());
3527 } else if (p == "use-video-sync") {
3529 waiting_for_sync_offset = config.get_use_video_sync();
3531 } else if (p == "mmc-control") {
3533 //poke_midi_thread ();
3535 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3537 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3539 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3541 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3543 } else if (p == "midi-control") {
3545 //poke_midi_thread ();
3547 } else if (p == "raid-path") {
3549 setup_raid_path (config.get_raid_path());
3551 } else if (p == "timecode-format") {
3555 } else if (p == "video-pullup") {
3559 } else if (p == "seamless-loop") {
3561 if (play_loop && transport_rolling()) {
3562 // to reset diskstreams etc
3563 request_play_loop (true);
3566 } else if (p == "rf-speed") {
3568 cumulative_rf_motion = 0;
3571 } else if (p == "click-sound") {
3573 setup_click_sounds (1);
3575 } else if (p == "click-emphasis-sound") {
3577 setup_click_sounds (-1);
3579 } else if (p == "clicking") {
3581 if (Config->get_clicking()) {
3582 if (_click_io && click_data) { // don't require emphasis data
3589 } else if (p == "click-gain") {
3592 _click_gain->set_gain (Config->get_click_gain(), this);
3595 } else if (p == "send-mtc") {
3597 if (Config->get_send_mtc ()) {
3598 /* mark us ready to send */
3599 next_quarter_frame_to_send = 0;
3602 } else if (p == "send-mmc") {
3604 _mmc->enable_send (Config->get_send_mmc ());
3606 } else if (p == "midi-feedback") {
3608 session_midi_feedback = Config->get_midi_feedback();
3610 } else if (p == "jack-time-master") {
3612 engine().reset_timebase ();
3614 } else if (p == "native-file-header-format") {
3616 if (!first_file_header_format_reset) {
3617 reset_native_file_format ();
3620 first_file_header_format_reset = false;
3622 } else if (p == "native-file-data-format") {
3624 if (!first_file_data_format_reset) {
3625 reset_native_file_format ();
3628 first_file_data_format_reset = false;
3630 } else if (p == "external-sync") {
3631 if (!config.get_external_sync()) {
3632 drop_sync_source ();
3634 switch_to_sync_source (Config->get_sync_source());
3636 } else if (p == "denormal-model") {
3638 } else if (p == "history-depth") {
3639 set_history_depth (Config->get_history_depth());
3640 } else if (p == "remote-model") {
3641 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3644 } else if (p == "initial-program-change") {
3646 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3649 buf[0] = MIDI::program; // channel zero by default
3650 buf[1] = (Config->get_initial_program_change() & 0x7f);
3652 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3654 } else if (p == "solo-mute-override") {
3655 // catch_up_on_solo_mute_override ();
3656 } else if (p == "listen-position" || p == "pfl-position") {
3657 listen_position_changed ();
3658 } else if (p == "solo-control-is-listen-control") {
3659 solo_control_mode_changed ();
3660 } else if (p == "solo-mute-gain") {
3661 _solo_cut_control->Changed();
3662 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3663 last_timecode_valid = false;
3664 } else if (p == "playback-buffer-seconds") {
3665 AudioSource::allocate_working_buffers (frame_rate());
3666 } else if (p == "ltc-source-port") {
3667 reconnect_ltc_input ();
3668 } else if (p == "ltc-sink-port") {
3669 reconnect_ltc_output ();
3670 } else if (p == "timecode-generator-offset") {
3671 ltc_tx_parse_offset();
3672 } else if (p == "auto-return-target-list") {
3673 follow_playhead_priority ();
3680 Session::set_history_depth (uint32_t d)
3682 _history.set_depth (d);
3686 Session::load_diskstreams_2X (XMLNode const & node, int)
3689 XMLNodeConstIterator citer;
3691 clist = node.children();
3693 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3696 /* diskstreams added automatically by DiskstreamCreated handler */
3697 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3698 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3699 _diskstreams_2X.push_back (dsp);
3701 error << _("Session: unknown diskstream type in XML") << endmsg;
3705 catch (failed_constructor& err) {
3706 error << _("Session: could not load diskstream via XML state") << endmsg;
3714 /** Connect things to the MMC object */
3716 Session::setup_midi_machine_control ()
3718 _mmc = new MIDI::MachineControl;
3719 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3721 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3722 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3723 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3724 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3725 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3726 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3727 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3728 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3729 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3730 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3731 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3732 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3733 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3735 /* also handle MIDI SPP because its so common */
3737 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3738 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3739 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3742 boost::shared_ptr<Controllable>
3743 Session::solo_cut_control() const
3745 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3746 controls in Ardour that currently get presented to the user in the GUI that require
3747 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3749 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3750 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3754 return _solo_cut_control;
3758 Session::rename (const std::string& new_name)
3760 string legal_name = legalize_for_path (new_name);
3766 string const old_sources_root = _session_dir->sources_root();
3768 if (!_writable || (_state_of_the_state & CannotSave)) {
3769 error << _("Cannot rename read-only session.") << endmsg;
3770 return 0; // don't show "messed up" warning
3772 if (record_status() == Recording) {
3773 error << _("Cannot rename session while recording") << endmsg;
3774 return 0; // don't show "messed up" warning
3777 StateProtector stp (this);
3782 * interchange subdirectory
3786 * Backup files are left unchanged and not renamed.
3789 /* Windows requires that we close all files before attempting the
3790 * rename. This works on other platforms, but isn't necessary there.
3791 * Leave it in place for all platforms though, since it may help
3792 * catch issues that could arise if the way Source files work ever
3793 * change (since most developers are not using Windows).
3796 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3797 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3803 /* pass one: not 100% safe check that the new directory names don't
3807 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3811 /* this is a stupid hack because Glib::path_get_dirname() is
3812 * lexical-only, and so passing it /a/b/c/ gives a different
3813 * result than passing it /a/b/c ...
3816 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3817 oldstr = oldstr.substr (0, oldstr.length() - 1);
3820 string base = Glib::path_get_dirname (oldstr);
3822 newstr = Glib::build_filename (base, legal_name);
3824 cerr << "Looking for " << newstr << endl;
3826 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3827 cerr << " exists\n";
3836 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3842 /* this is a stupid hack because Glib::path_get_dirname() is
3843 * lexical-only, and so passing it /a/b/c/ gives a different
3844 * result than passing it /a/b/c ...
3847 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3848 oldstr = oldstr.substr (0, oldstr.length() - 1);
3851 string base = Glib::path_get_dirname (oldstr);
3852 newstr = Glib::build_filename (base, legal_name);
3854 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3856 cerr << "Rename " << oldstr << " => " << newstr << endl;
3857 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3858 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3859 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3863 /* Reset path in "session dirs" */
3868 /* reset primary SessionDirectory object */
3871 (*_session_dir) = newstr;
3876 /* now rename directory below session_dir/interchange */
3878 string old_interchange_dir;
3879 string new_interchange_dir;
3881 /* use newstr here because we renamed the path
3882 * (folder/directory) that used to be oldstr to newstr above
3885 v.push_back (newstr);
3886 v.push_back (interchange_dir_name);
3887 v.push_back (Glib::path_get_basename (oldstr));
3889 old_interchange_dir = Glib::build_filename (v);
3892 v.push_back (newstr);
3893 v.push_back (interchange_dir_name);
3894 v.push_back (legal_name);
3896 new_interchange_dir = Glib::build_filename (v);
3898 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3900 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3901 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3902 old_interchange_dir, new_interchange_dir,
3905 error << string_compose (_("renaming %s as %2 failed (%3)"),
3906 old_interchange_dir, new_interchange_dir,
3915 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3916 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3918 cerr << "Rename " << oldstr << " => " << newstr << endl;
3920 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3921 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3922 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3928 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3930 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3931 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3933 cerr << "Rename " << oldstr << " => " << newstr << endl;
3935 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3936 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3937 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3942 /* remove old name from recent sessions */
3943 remove_recent_sessions (_path);
3946 /* update file source paths */
3948 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3949 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3951 string p = fs->path ();
3952 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3954 SourceFactory::setup_peakfile(i->second, true);
3958 _current_snapshot_name = new_name;
3963 /* save state again to get everything just right */
3965 save_state (_current_snapshot_name);
3967 /* add to recent sessions */
3969 store_recent_sessions (new_name, _path);
3975 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3977 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3981 if (!tree.read (xmlpath)) {
3989 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3992 bool found_sr = false;
3993 bool found_data_format = false;
3995 if (get_session_info_from_path (tree, xmlpath)) {
4001 const XMLProperty* prop;
4002 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4003 sample_rate = atoi (prop->value());
4007 const XMLNodeList& children (tree.root()->children());
4008 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4009 const XMLNode* child = *c;
4010 if (child->name() == "Config") {
4011 const XMLNodeList& options (child->children());
4012 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4013 const XMLNode* option = *oc;
4014 const XMLProperty* name = option->property("name");
4020 if (name->value() == "native-file-data-format") {
4021 const XMLProperty* value = option->property ("value");
4023 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4025 found_data_format = true;
4031 if (found_data_format) {
4036 return !(found_sr && found_data_format); // zero if they are both found
4039 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4040 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4043 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4047 SourcePathMap source_path_map;
4049 boost::shared_ptr<AudioFileSource> afs;
4054 Glib::Threads::Mutex::Lock lm (source_lock);
4056 cerr << " total sources = " << sources.size();
4058 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4059 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4065 if (fs->within_session()) {
4069 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4070 source_path_map[fs->path()].push_back (fs);
4072 SeveralFileSources v;
4074 source_path_map.insert (make_pair (fs->path(), v));
4080 cerr << " fsources = " << total << endl;
4082 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4084 /* tell caller where we are */
4086 string old_path = i->first;
4088 callback (n, total, old_path);
4090 cerr << old_path << endl;
4094 switch (i->second.front()->type()) {
4095 case DataType::AUDIO:
4096 new_path = new_audio_source_path_for_embedded (old_path);
4099 case DataType::MIDI:
4100 /* XXX not implemented yet */
4104 if (new_path.empty()) {
4108 cerr << "Move " << old_path << " => " << new_path << endl;
4110 if (!copy_file (old_path, new_path)) {
4111 cerr << "failed !\n";
4115 /* make sure we stop looking in the external
4116 dir/folder. Remember, this is an all-or-nothing
4117 operations, it doesn't merge just some files.
4119 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4121 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4122 (*f)->set_path (new_path);
4127 save_state ("", false, false);
4133 bool accept_all_files (string const &, void *)
4139 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4141 /* 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.
4146 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4148 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4150 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4152 v.push_back (new_session_folder); /* full path */
4153 v.push_back (interchange_dir_name);
4154 v.push_back (new_session_path); /* just one directory/folder */
4155 v.push_back (typedir);
4156 v.push_back (Glib::path_get_basename (old_path));
4158 return Glib::build_filename (v);
4162 Session::save_as (SaveAs& saveas)
4164 vector<string> files;
4165 string current_folder = Glib::path_get_dirname (_path);
4166 string new_folder = legalize_for_path (saveas.new_name);
4167 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4168 int64_t total_bytes = 0;
4172 int32_t internal_file_cnt = 0;
4174 vector<string> do_not_copy_extensions;
4175 do_not_copy_extensions.push_back (statefile_suffix);
4176 do_not_copy_extensions.push_back (pending_suffix);
4177 do_not_copy_extensions.push_back (backup_suffix);
4178 do_not_copy_extensions.push_back (temp_suffix);
4179 do_not_copy_extensions.push_back (history_suffix);
4181 /* get total size */
4183 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4185 /* need to clear this because
4186 * find_files_matching_filter() is cumulative
4191 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4193 all += files.size();
4195 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4197 g_stat ((*i).c_str(), &gsb);
4198 total_bytes += gsb.st_size;
4202 /* save old values so we can switch back if we are not switching to the new session */
4204 string old_path = _path;
4205 string old_name = _name;
4206 string old_snapshot = _current_snapshot_name;
4207 string old_sd = _session_dir->root_path();
4208 vector<string> old_search_path[DataType::num_types];
4209 string old_config_search_path[DataType::num_types];
4211 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4212 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4213 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4214 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4216 /* switch session directory */
4218 (*_session_dir) = to_dir;
4220 /* create new tree */
4222 if (!_session_dir->create()) {
4223 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4228 /* copy all relevant files. Find each location in session_dirs,
4229 * and copy files from there to target.
4232 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4234 /* need to clear this because
4235 * find_files_matching_filter() is cumulative
4240 const size_t prefix_len = (*sd).path.size();
4242 /* Work just on the files within this session dir */
4244 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4246 /* add dir separator to protect against collisions with
4247 * track names (e.g. track named "audiofiles" or
4251 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4252 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4253 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4255 /* copy all the files. Handling is different for media files
4256 than others because of the *silly* subtree we have below the interchange
4257 folder. That really was a bad idea, but I'm not fixing it as part of
4258 implementing ::save_as().
4261 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4263 std::string from = *i;
4266 string filename = Glib::path_get_basename (from);
4267 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4268 if (filename == ".DS_STORE") {
4273 if (from.find (audiofile_dir_string) != string::npos) {
4275 /* audio file: only copy if asked */
4277 if (saveas.include_media && saveas.copy_media) {
4279 string to = make_new_media_path (*i, to_dir, new_folder);
4281 info << "media file copying from " << from << " to " << to << endmsg;
4283 if (!copy_file (from, to)) {
4284 throw Glib::FileError (Glib::FileError::IO_ERROR,
4285 string_compose(_("\ncopying \"%1\" failed !"), from));
4289 /* we found media files inside the session folder */
4291 internal_file_cnt++;
4293 } else if (from.find (midifile_dir_string) != string::npos) {
4295 /* midi file: always copy unless
4296 * creating an empty new session
4299 if (saveas.include_media) {
4301 string to = make_new_media_path (*i, to_dir, new_folder);
4303 info << "media file copying from " << from << " to " << to << endmsg;
4305 if (!copy_file (from, to)) {
4306 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4310 /* we found media files inside the session folder */
4312 internal_file_cnt++;
4314 } else if (from.find (analysis_dir_string) != string::npos) {
4316 /* make sure analysis dir exists in
4317 * new session folder, but we're not
4318 * copying analysis files here, see
4322 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4327 /* normal non-media file. Don't copy state, history, etc.
4330 bool do_copy = true;
4332 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4333 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4334 /* end of filename matches extension, do not copy file */
4340 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4341 /* don't copy peakfiles if
4342 * we're not copying media
4348 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4350 info << "attempting to make directory/folder " << to << endmsg;
4352 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4353 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4356 info << "attempting to copy " << from << " to " << to << endmsg;
4358 if (!copy_file (from, to)) {
4359 throw Glib::FileError (Glib::FileError::IO_ERROR,
4360 string_compose(_("\ncopying \"%1\" failed !"), from));
4365 /* measure file size even if we're not going to copy so that our Progress
4366 signals are correct, since we included these do-not-copy files
4367 in the computation of the total size and file count.
4371 g_stat (from.c_str(), &gsb);
4372 copied += gsb.st_size;
4375 double fraction = (double) copied / total_bytes;
4377 bool keep_going = true;
4379 if (saveas.copy_media) {
4381 /* no need or expectation of this if
4382 * media is not being copied, because
4383 * it will be fast(ish).
4386 /* tell someone "X percent, file M of N"; M is one-based */
4388 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4396 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4402 /* copy optional folders, if any */
4404 string old = plugins_dir ();
4405 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4406 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4407 copy_files (old, newdir);
4410 old = externals_dir ();
4411 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4412 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4413 copy_files (old, newdir);
4416 old = automation_dir ();
4417 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4418 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4419 copy_files (old, newdir);
4422 if (saveas.include_media) {
4424 if (saveas.copy_media) {
4425 #ifndef PLATFORM_WINDOWS
4426 /* There are problems with analysis files on
4427 * Windows, because they used a colon in their
4428 * names as late as 4.0. Colons are not legal
4429 * under Windows even if NTFS allows them.
4431 * This is a tricky problem to solve so for
4432 * just don't copy these files. They will be
4433 * regenerated as-needed anyway, subject to the
4434 * existing issue that the filenames will be
4435 * rejected by Windows, which is a separate
4436 * problem (though related).
4439 /* only needed if we are copying media, since the
4440 * analysis data refers to media data
4443 old = analysis_dir ();
4444 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4445 string newdir = Glib::build_filename (to_dir, "analysis");
4446 copy_files (old, newdir);
4448 #endif /* PLATFORM_WINDOWS */
4454 _current_snapshot_name = saveas.new_name;
4455 _name = saveas.new_name;
4457 if (saveas.include_media && !saveas.copy_media) {
4459 /* reset search paths of the new session (which we're pretending to be right now) to
4460 include the original session search path, so we can still find all audio.
4463 if (internal_file_cnt) {
4464 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4465 ensure_search_path_includes (*s, DataType::AUDIO);
4466 cerr << "be sure to include " << *s << " for audio" << endl;
4469 /* we do not do this for MIDI because we copy
4470 all MIDI files if saveas.include_media is
4476 bool was_dirty = dirty ();
4478 save_state ("", false, false, !saveas.include_media);
4479 save_default_options ();
4481 if (saveas.copy_media && saveas.copy_external) {
4482 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4483 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4487 saveas.final_session_folder_name = _path;
4489 store_recent_sessions (_name, _path);
4491 if (!saveas.switch_to) {
4493 /* switch back to the way things were */
4497 _current_snapshot_name = old_snapshot;
4499 (*_session_dir) = old_sd;
4505 if (internal_file_cnt) {
4506 /* reset these to their original values */
4507 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4508 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4513 /* prune session dirs, and update disk space statistics
4518 session_dirs.clear ();
4519 session_dirs.push_back (sp);
4520 refresh_disk_space ();
4522 /* ensure that all existing tracks reset their current capture source paths
4524 reset_write_sources (true, true);
4526 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4527 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4530 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4531 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4537 if (fs->within_session()) {
4538 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4539 fs->set_path (newpath);
4544 } catch (Glib::FileError& e) {
4546 saveas.failure_message = e.what();
4548 /* recursively remove all the directories */
4550 remove_directory (to_dir);
4558 saveas.failure_message = _("unknown reason");
4560 /* recursively remove all the directories */
4562 remove_directory (to_dir);