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"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.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/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/sndfilesource.h"
124 #include "ardour/source_factory.h"
125 #include "ardour/speakers.h"
126 #include "ardour/template_utils.h"
127 #include "ardour/tempo.h"
128 #include "ardour/ticker.h"
129 #include "ardour/user_bundle.h"
130 #include "ardour/vca.h"
131 #include "ardour/vca_manager.h"
133 #include "control_protocol/control_protocol.h"
135 #include "LuaBridge/LuaBridge.h"
137 #include "pbd/i18n.h"
141 using namespace ARDOUR;
144 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
147 Session::pre_engine_init (string fullpath)
149 if (fullpath.empty()) {
151 throw failed_constructor();
154 /* discover canonical fullpath */
156 _path = canonical_path(fullpath);
159 if (Profile->get_trx() ) {
160 // Waves TracksLive has a usecase of session replacement with a new one.
161 // We should check session state file (<session_name>.ardour) existance
162 // to determine if the session is new or not
164 string full_session_name = Glib::build_filename( fullpath, _name );
165 full_session_name += statefile_suffix;
167 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
169 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 /* finish initialization that can't be done in a normal C++ constructor
176 timerclear (&last_mmc_step);
177 g_atomic_int_set (&processing_prohibited, 0);
178 g_atomic_int_set (&_record_status, Disabled);
179 g_atomic_int_set (&_playback_load, 100);
180 g_atomic_int_set (&_capture_load, 100);
182 _all_route_group->set_active (true, this);
183 interpolation.add_channel_to (0, 0);
185 if (config.get_use_video_sync()) {
186 waiting_for_sync_offset = true;
188 waiting_for_sync_offset = false;
191 last_rr_session_dir = session_dirs.begin();
193 set_history_depth (Config->get_history_depth());
195 /* default: assume simple stereo speaker configuration */
197 _speakers->setup_default_speakers (2);
199 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
200 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
201 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
202 add_controllable (_solo_cut_control);
204 /* These are all static "per-class" signals */
206 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
207 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
208 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
209 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
210 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
212 /* stop IO objects from doing stuff until we're ready for them */
214 Delivery::disable_panners ();
215 IO::disable_connecting ();
219 Session::post_engine_init ()
221 BootMessage (_("Set block size and sample rate"));
223 set_block_size (_engine.samples_per_cycle());
224 set_frame_rate (_engine.sample_rate());
226 BootMessage (_("Using configuration"));
228 _midi_ports = new MidiPortManager;
230 MIDISceneChanger* msc;
232 _scene_changer = msc = new MIDISceneChanger (*this);
233 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
234 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
236 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
237 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
239 setup_midi_machine_control ();
241 if (_butler->start_thread()) {
242 error << _("Butler did not start") << endmsg;
246 if (start_midi_thread ()) {
247 error << _("MIDI I/O thread did not start") << endmsg;
251 setup_click_sounds (0);
252 setup_midi_control ();
254 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
255 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
258 /* tempo map requires sample rate knowledge */
261 _tempo_map = new TempoMap (_current_frame_rate);
262 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
263 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
265 /* MidiClock requires a tempo map */
268 midi_clock = new MidiClockTicker ();
269 midi_clock->set_session (this);
271 /* crossfades require sample rate knowledge */
273 SndFileSource::setup_standard_crossfades (*this, frame_rate());
274 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
275 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
277 AudioDiskstream::allocate_working_buffers();
278 refresh_disk_space ();
280 /* we're finally ready to call set_state() ... all objects have
281 * been created, the engine is running.
285 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
286 error << _("Could not set session state from XML") << endmsg;
290 // set_state() will call setup_raid_path(), but if it's a new session we need
291 // to call setup_raid_path() here.
292 setup_raid_path (_path);
297 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
298 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
300 Config->map_parameters (ff);
301 config.map_parameters (ft);
302 _butler->map_parameters ();
304 /* Reset all panners */
306 Delivery::reset_panners ();
308 /* this will cause the CPM to instantiate any protocols that are in use
309 * (or mandatory), which will pass it this Session, and then call
310 * set_state() on each instantiated protocol to match stored state.
313 ControlProtocolManager::instance().set_session (this);
315 /* This must be done after the ControlProtocolManager set_session above,
316 as it will set states for ports which the ControlProtocolManager creates.
319 // XXX set state of MIDI::Port's
320 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
322 /* And this must be done after the MIDI::Manager::set_port_states as
323 * it will try to make connections whose details are loaded by set_port_states.
328 /* Let control protocols know that we are now all connected, so they
329 * could start talking to surfaces if they want to.
332 ControlProtocolManager::instance().midi_connectivity_established ();
334 if (_is_new && !no_auto_connect()) {
335 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
336 auto_connect_master_bus ();
339 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
341 /* update latencies */
343 initialize_latencies ();
345 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
346 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
347 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
349 } catch (AudioEngine::PortRegistrationFailure& err) {
350 /* handle this one in a different way than all others, so that its clear what happened */
351 error << err.what() << endmsg;
353 } catch (std::exception const & e) {
354 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
357 error << _("Unknown exception during session setup") << endmsg;
361 BootMessage (_("Reset Remote Controls"));
363 // send_full_time_code (0);
364 _engine.transport_locate (0);
366 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
367 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
369 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
372 /* initial program change will be delivered later; see ::config_changed() */
374 _state_of_the_state = Clean;
376 Port::set_connecting_blocked (false);
378 DirtyChanged (); /* EMIT SIGNAL */
382 } else if (state_was_pending) {
384 remove_pending_capture_state ();
385 state_was_pending = false;
388 /* Now, finally, we can fill the playback buffers */
390 BootMessage (_("Filling playback buffers"));
392 boost::shared_ptr<RouteList> rl = routes.reader();
393 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
394 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
395 if (trk && !trk->hidden()) {
396 trk->seek (_transport_frame, true);
404 Session::session_loaded ()
408 _state_of_the_state = Clean;
410 DirtyChanged (); /* EMIT SIGNAL */
414 } else if (state_was_pending) {
416 remove_pending_capture_state ();
417 state_was_pending = false;
420 /* Now, finally, we can fill the playback buffers */
422 BootMessage (_("Filling playback buffers"));
423 force_locate (_transport_frame, false);
427 Session::raid_path () const
429 Searchpath raid_search_path;
431 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
432 raid_search_path += (*i).path;
435 return raid_search_path.to_string ();
439 Session::setup_raid_path (string path)
448 session_dirs.clear ();
450 Searchpath search_path(path);
451 Searchpath sound_search_path;
452 Searchpath midi_search_path;
454 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
456 sp.blocks = 0; // not needed
457 session_dirs.push_back (sp);
459 SessionDirectory sdir(sp.path);
461 sound_search_path += sdir.sound_path ();
462 midi_search_path += sdir.midi_path ();
465 // reset the round-robin soundfile path thingie
466 last_rr_session_dir = session_dirs.begin();
470 Session::path_is_within_session (const std::string& path)
472 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
473 if (PBD::path_is_within (i->path, path)) {
481 Session::ensure_subdirs ()
485 dir = session_directory().peak_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().sound_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = session_directory().midi_path();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = session_directory().dead_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().export_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = analysis_dir ();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = plugins_dir ();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = externals_dir ();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
544 /** @param session_template directory containing session template, or empty.
545 * Caller must not hold process lock.
548 Session::create (const string& session_template, BusProfile* bus_profile)
550 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
551 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
555 if (ensure_subdirs ()) {
559 _writable = exists_and_writable (_path);
561 if (!session_template.empty()) {
562 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
564 FILE* in = g_fopen (in_path.c_str(), "rb");
567 /* no need to call legalize_for_path() since the string
568 * in session_template is already a legal path name
570 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
572 FILE* out = g_fopen (out_path.c_str(), "wb");
576 stringstream new_session;
579 size_t charsRead = fread (buf, sizeof(char), 1024, in);
582 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
587 if (charsRead == 0) {
590 new_session.write (buf, charsRead);
594 string file_contents = new_session.str();
595 size_t writeSize = file_contents.length();
596 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
597 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
605 if (!ARDOUR::Profile->get_trx()) {
606 /* Copy plugin state files from template to new session */
607 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
608 copy_recurse (template_plugins, plugins_dir ());
614 error << string_compose (_("Could not open %1 for writing session template"), out_path)
621 error << string_compose (_("Could not open session template %1 for reading"), in_path)
628 if (Profile->get_trx()) {
630 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
631 Remember that this is a brand new session. Sessions
632 loaded from saved state will get this range from the saved state.
635 set_session_range_location (0, 0);
637 /* Initial loop location, from absolute zero, length 10 seconds */
639 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
640 _locations->add (loc, true);
641 set_auto_loop_location (loc);
644 _state_of_the_state = Clean;
646 /* set up Master Out and Monitor Out if necessary */
651 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
653 // Waves Tracks: always create master bus for Tracks
654 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
655 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
663 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
664 r->input()->ensure_io (count, false, this);
665 r->output()->ensure_io (count, false, this);
671 /* prohibit auto-connect to master, because there isn't one */
672 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
676 add_routes (rl, false, false, false, PresentationInfo::max_order);
679 // Waves Tracks: Skip this. Always use autoconnection for Tracks
680 if (!ARDOUR::Profile->get_trx()) {
682 /* this allows the user to override settings with an environment variable.
685 if (no_auto_connect()) {
686 bus_profile->input_ac = AutoConnectOption (0);
687 bus_profile->output_ac = AutoConnectOption (0);
690 Config->set_input_auto_connect (bus_profile->input_ac);
691 Config->set_output_auto_connect (bus_profile->output_ac);
695 if (Config->get_use_monitor_bus() && bus_profile) {
696 add_monitor_section ();
703 Session::maybe_write_autosave()
705 if (dirty() && record_status() != Recording) {
706 save_state("", true);
711 Session::remove_pending_capture_state ()
713 std::string pending_state_file_path(_session_dir->root_path());
715 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
717 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
719 if (g_remove (pending_state_file_path.c_str()) != 0) {
720 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
721 pending_state_file_path, g_strerror (errno)) << endmsg;
725 /** Rename a state file.
726 * @param old_name Old snapshot name.
727 * @param new_name New snapshot name.
730 Session::rename_state (string old_name, string new_name)
732 if (old_name == _current_snapshot_name || old_name == _name) {
733 /* refuse to rename the current snapshot or the "main" one */
737 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
738 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
740 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
741 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
743 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
744 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
745 old_name, new_name, g_strerror(errno)) << endmsg;
749 /** Remove a state file.
750 * @param snapshot_name Snapshot name.
753 Session::remove_state (string snapshot_name)
755 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
756 // refuse to remove the current snapshot or the "main" one
760 std::string xml_path(_session_dir->root_path());
762 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
764 if (!create_backup_file (xml_path)) {
765 // don't remove it if a backup can't be made
766 // create_backup_file will log the error.
771 if (g_remove (xml_path.c_str()) != 0) {
772 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
773 xml_path, g_strerror (errno)) << endmsg;
777 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
779 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
781 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
784 std::string xml_path(_session_dir->root_path());
786 /* prevent concurrent saves from different threads */
788 Glib::Threads::Mutex::Lock lm (save_state_lock);
790 if (!_writable || (_state_of_the_state & CannotSave)) {
794 if (g_atomic_int_get(&_suspend_save)) {
798 _save_queued = false;
800 if (!_engine.connected ()) {
801 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
808 const int64_t save_start_time = g_get_monotonic_time();
811 /* tell sources we're saving first, in case they write out to a new file
812 * which should be saved with the state rather than the old one */
813 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
815 i->second->session_saved();
816 } catch (Evoral::SMF::FileError& e) {
817 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
821 SessionSaveUnderway (); /* EMIT SIGNAL */
823 bool mark_as_clean = true;
825 if (!snapshot_name.empty() && !switch_to_snapshot) {
826 mark_as_clean = false;
830 mark_as_clean = false;
831 tree.set_root (&get_template());
833 tree.set_root (&get_state());
836 if (snapshot_name.empty()) {
837 snapshot_name = _current_snapshot_name;
838 } else if (switch_to_snapshot) {
839 set_snapshot_name (snapshot_name);
842 assert (!snapshot_name.empty());
846 /* proper save: use statefile_suffix (.ardour in English) */
848 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
850 /* make a backup copy of the old file */
852 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
853 // create_backup_file will log the error
859 /* pending save: use pending_suffix (.pending in English) */
860 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
863 std::string tmp_path(_session_dir->root_path());
864 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
866 cerr << "actually writing state to " << tmp_path << endl;
868 if (!tree.write (tmp_path)) {
869 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 cerr << "renaming state to " << xml_path << endl;
880 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
881 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
882 tmp_path, xml_path, g_strerror(errno)) << endmsg;
883 if (g_remove (tmp_path.c_str()) != 0) {
884 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
885 tmp_path, g_strerror (errno)) << endmsg;
893 save_history (snapshot_name);
896 bool was_dirty = dirty();
898 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
901 DirtyChanged (); /* EMIT SIGNAL */
905 StateSaved (snapshot_name); /* EMIT SIGNAL */
909 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
910 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
916 Session::restore_state (string snapshot_name)
918 if (load_state (snapshot_name) == 0) {
919 set_state (*state_tree->root(), Stateful::loading_state_version);
926 Session::load_state (string snapshot_name)
931 state_was_pending = false;
933 /* check for leftover pending state from a crashed capture attempt */
935 std::string xmlpath(_session_dir->root_path());
936 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
938 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 /* there is pending state from a crashed capture attempt */
942 boost::optional<int> r = AskAboutPendingState();
943 if (r.get_value_or (1)) {
944 state_was_pending = true;
948 if (!state_was_pending) {
949 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
952 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
953 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
954 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
955 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
960 state_tree = new XMLTree;
964 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
966 if (!state_tree->read (xmlpath)) {
967 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
973 XMLNode const & root (*state_tree->root());
975 if (root.name() != X_("Session")) {
976 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
982 XMLProperty const * prop;
984 if ((prop = root.property ("version")) == 0) {
985 /* no version implies very old version of Ardour */
986 Stateful::loading_state_version = 1000;
988 if (prop->value().find ('.') != string::npos) {
989 /* old school version format */
990 if (prop->value()[0] == '2') {
991 Stateful::loading_state_version = 2000;
993 Stateful::loading_state_version = 3000;
996 Stateful::loading_state_version = atoi (prop->value());
1000 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1002 std::string backup_path(_session_dir->root_path());
1003 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1004 backup_path = Glib::build_filename (backup_path, backup_filename);
1006 // only create a backup for a given statefile version once
1008 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1010 VersionMismatch (xmlpath, backup_path);
1012 if (!copy_file (xmlpath, backup_path)) {;
1018 save_snapshot_name (snapshot_name);
1024 Session::load_options (const XMLNode& node)
1027 config.set_variables (node);
1032 Session::save_default_options ()
1034 return config.save_state();
1038 Session::get_state()
1044 Session::get_template()
1046 /* if we don't disable rec-enable, diskstreams
1047 will believe they need to store their capture
1048 sources in their state node.
1051 disable_record (false);
1053 return state(false);
1056 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1057 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1060 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1062 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1065 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1069 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1072 XMLNode* node = new XMLNode("TrackState"); // XXX
1075 PlaylistSet playlists; // SessionPlaylists
1078 // these will work with new_route_from_template()
1079 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1080 child = node->add_child ("Routes");
1081 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1082 if ((*i)->is_auditioner()) {
1085 if ((*i)->is_master() || (*i)->is_monitor()) {
1088 child->add_child_nocopy ((*i)->get_state());
1089 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1091 playlists.insert (track->playlist ());
1095 // on load, Regions in the playlists need to resolve and map Source-IDs
1096 // also playlist needs to be merged or created with new-name..
1097 // ... and Diskstream in tracks adjusted to use the correct playlist
1098 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1099 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1100 child->add_child_nocopy ((*i)->get_state ());
1101 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1102 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1103 const Region::SourceList& sl = (*s)->sources ();
1104 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1105 sources.insert (*sli);
1110 child = node->add_child ("Sources");
1111 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1112 child->add_child_nocopy ((*i)->get_state ());
1113 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1115 #ifdef PLATFORM_WINDOWS
1118 string p = fs->path ();
1119 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1123 std::string sn = Glib::build_filename (path, "share.axml");
1126 tree.set_root (node);
1127 return tree.write (sn.c_str());
1131 Session::state (bool full_state)
1134 XMLNode* node = new XMLNode("Session");
1138 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1139 node->add_property("version", buf);
1141 child = node->add_child ("ProgramVersion");
1142 child->add_property("created-with", created_with);
1144 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1145 child->add_property("modified-with", modified_with);
1147 /* store configuration settings */
1151 node->add_property ("name", _name);
1152 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1153 node->add_property ("sample-rate", buf);
1155 if (session_dirs.size() > 1) {
1159 vector<space_and_path>::iterator i = session_dirs.begin();
1160 vector<space_and_path>::iterator next;
1162 ++i; /* skip the first one */
1166 while (i != session_dirs.end()) {
1170 if (next != session_dirs.end()) {
1171 p += G_SEARCHPATH_SEPARATOR;
1180 child = node->add_child ("Path");
1181 child->add_content (p);
1185 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1187 /* save the ID counter */
1189 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1190 node->add_property ("id-counter", buf);
1192 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1193 node->add_property ("name-counter", buf);
1195 /* save the event ID counter */
1197 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1198 node->add_property ("event-counter", buf);
1200 /* save the VCA counter */
1202 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1203 node->add_property ("vca-counter", buf);
1205 /* various options */
1207 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1208 if (!midi_port_nodes.empty()) {
1209 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1210 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1211 midi_port_stuff->add_child_nocopy (**n);
1213 node->add_child_nocopy (*midi_port_stuff);
1216 XMLNode& cfgxml (config.get_variables ());
1218 /* exclude search-paths from template */
1219 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1220 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1221 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1223 node->add_child_nocopy (cfgxml);
1225 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1227 child = node->add_child ("Sources");
1230 Glib::Threads::Mutex::Lock sl (source_lock);
1232 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1234 /* Don't save information about non-file Sources, or
1235 * about non-destructive file sources that are empty
1236 * and unused by any regions.
1239 boost::shared_ptr<FileSource> fs;
1241 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1243 if (!fs->destructive()) {
1244 if (fs->empty() && !fs->used()) {
1249 child->add_child_nocopy (siter->second->get_state());
1254 child = node->add_child ("Regions");
1257 Glib::Threads::Mutex::Lock rl (region_lock);
1258 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1259 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1260 boost::shared_ptr<Region> r = i->second;
1261 /* only store regions not attached to playlists */
1262 if (r->playlist() == 0) {
1263 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1264 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1266 child->add_child_nocopy (r->get_state ());
1271 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1273 if (!cassocs.empty()) {
1274 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1276 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1278 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1279 i->first->id().print (buf, sizeof (buf));
1280 can->add_property (X_("copy"), buf);
1281 i->second->id().print (buf, sizeof (buf));
1282 can->add_property (X_("original"), buf);
1283 ca->add_child_nocopy (*can);
1293 node->add_child_nocopy (_locations->get_state());
1296 Locations loc (*this);
1297 // for a template, just create a new Locations, populate it
1298 // with the default start and end, and get the state for that.
1299 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1300 range->set (max_framepos, 0);
1302 XMLNode& locations_state = loc.get_state();
1304 if (ARDOUR::Profile->get_trx() && _locations) {
1305 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1306 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1307 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1308 locations_state.add_child_nocopy ((*i)->get_state ());
1312 node->add_child_nocopy (locations_state);
1315 child = node->add_child ("Bundles");
1317 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1318 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1319 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1321 child->add_child_nocopy (b->get_state());
1326 node->add_child_nocopy (_vca_manager->get_state());
1328 child = node->add_child ("Routes");
1330 boost::shared_ptr<RouteList> r = routes.reader ();
1332 RoutePublicOrderSorter cmp;
1333 RouteList public_order (*r);
1334 public_order.sort (cmp);
1336 /* the sort should have put the monitor out first */
1339 assert (_monitor_out == public_order.front());
1342 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1343 if (!(*i)->is_auditioner()) {
1345 child->add_child_nocopy ((*i)->get_state());
1347 child->add_child_nocopy ((*i)->get_template());
1353 playlists->add_state (node, full_state);
1355 child = node->add_child ("RouteGroups");
1356 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1357 child->add_child_nocopy ((*i)->get_state());
1361 XMLNode* gain_child = node->add_child ("Click");
1362 gain_child->add_child_nocopy (_click_io->state (full_state));
1363 gain_child->add_child_nocopy (_click_gain->state (full_state));
1367 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1368 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1372 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1373 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1376 node->add_child_nocopy (_speakers->get_state());
1377 node->add_child_nocopy (_tempo_map->get_state());
1378 node->add_child_nocopy (get_control_protocol_state());
1381 node->add_child_copy (*_extra_xml);
1385 Glib::Threads::Mutex::Lock lm (lua_lock);
1388 luabridge::LuaRef savedstate ((*_lua_save)());
1389 saved = savedstate.cast<std::string>();
1391 lua.collect_garbage ();
1394 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1395 std::string b64s (b64);
1398 XMLNode* script_node = new XMLNode (X_("Script"));
1399 script_node->add_property (X_("lua"), LUA_VERSION);
1400 script_node->add_content (b64s);
1401 node->add_child_nocopy (*script_node);
1408 Session::get_control_protocol_state ()
1410 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1411 return cpm.get_state();
1415 Session::set_state (const XMLNode& node, int version)
1420 XMLProperty const * prop;
1423 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1425 if (node.name() != X_("Session")) {
1426 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1430 if ((prop = node.property ("name")) != 0) {
1431 _name = prop->value ();
1434 if ((prop = node.property (X_("sample-rate"))) != 0) {
1436 _base_frame_rate = atoi (prop->value());
1437 _nominal_frame_rate = _base_frame_rate;
1439 assert (AudioEngine::instance()->running ());
1440 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1441 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1442 if (r.get_value_or (0)) {
1448 created_with = "unknown";
1449 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1450 if ((prop = child->property (X_("created-with"))) != 0) {
1451 created_with = prop->value ();
1455 setup_raid_path(_session_dir->root_path());
1457 if ((prop = node.property (X_("end-is-free"))) != 0) {
1458 _session_range_end_is_free = string_is_affirmative (prop->value());
1461 if ((prop = node.property (X_("id-counter"))) != 0) {
1463 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1464 ID::init_counter (x);
1466 /* old sessions used a timebased counter, so fake
1467 the startup ID counter based on a standard
1472 ID::init_counter (now);
1475 if ((prop = node.property (X_("name-counter"))) != 0) {
1476 init_name_id_counter (atoi (prop->value()));
1479 if ((prop = node.property (X_("event-counter"))) != 0) {
1480 Evoral::init_event_id_counter (atoi (prop->value()));
1483 if ((prop = node.property (X_("vca-counter"))) != 0) {
1485 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1486 VCA::set_next_vca_number (x);
1488 VCA::set_next_vca_number (1);
1491 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1492 _midi_ports->set_midi_port_states (child->children());
1495 IO::disable_connecting ();
1497 Stateful::save_extra_xml (node);
1499 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1500 load_options (*child);
1501 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1502 load_options (*child);
1504 error << _("Session: XML state has no options section") << endmsg;
1507 if (version >= 3000) {
1508 if ((child = find_named_node (node, "Metadata")) == 0) {
1509 warning << _("Session: XML state has no metadata section") << endmsg;
1510 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1515 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1516 _speakers->set_state (*child, version);
1519 if ((child = find_named_node (node, "Sources")) == 0) {
1520 error << _("Session: XML state has no sources section") << endmsg;
1522 } else if (load_sources (*child)) {
1526 if ((child = find_named_node (node, "TempoMap")) == 0) {
1527 error << _("Session: XML state has no Tempo Map section") << endmsg;
1529 } else if (_tempo_map->set_state (*child, version)) {
1533 if ((child = find_named_node (node, "Locations")) == 0) {
1534 error << _("Session: XML state has no locations section") << endmsg;
1536 } else if (_locations->set_state (*child, version)) {
1540 locations_changed ();
1542 if (_session_range_location) {
1543 AudioFileSource::set_header_position_offset (_session_range_location->start());
1546 if ((child = find_named_node (node, "Regions")) == 0) {
1547 error << _("Session: XML state has no Regions section") << endmsg;
1549 } else if (load_regions (*child)) {
1553 if ((child = find_named_node (node, "Playlists")) == 0) {
1554 error << _("Session: XML state has no playlists section") << endmsg;
1556 } else if (playlists->load (*this, *child)) {
1560 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1562 } else if (playlists->load_unused (*this, *child)) {
1566 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1567 if (load_compounds (*child)) {
1572 if (version >= 3000) {
1573 if ((child = find_named_node (node, "Bundles")) == 0) {
1574 warning << _("Session: XML state has no bundles section") << endmsg;
1577 /* We can't load Bundles yet as they need to be able
1578 to convert from port names to Port objects, which can't happen until
1580 _bundle_xml_node = new XMLNode (*child);
1584 if (version < 3000) {
1585 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1586 error << _("Session: XML state has no diskstreams section") << endmsg;
1588 } else if (load_diskstreams_2X (*child, version)) {
1593 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1594 _vca_manager->set_state (*child, version);
1597 if ((child = find_named_node (node, "Routes")) == 0) {
1598 error << _("Session: XML state has no routes section") << endmsg;
1600 } else if (load_routes (*child, version)) {
1604 /* Now that we have Routes and masters loaded, connect them if appropriate */
1606 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1608 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1609 _diskstreams_2X.clear ();
1611 if (version >= 3000) {
1613 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1614 error << _("Session: XML state has no route groups section") << endmsg;
1616 } else if (load_route_groups (*child, version)) {
1620 } else if (version < 3000) {
1622 if ((child = find_named_node (node, "EditGroups")) == 0) {
1623 error << _("Session: XML state has no edit groups section") << endmsg;
1625 } else if (load_route_groups (*child, version)) {
1629 if ((child = find_named_node (node, "MixGroups")) == 0) {
1630 error << _("Session: XML state has no mix groups section") << endmsg;
1632 } else if (load_route_groups (*child, version)) {
1637 if ((child = find_named_node (node, "Click")) == 0) {
1638 warning << _("Session: XML state has no click section") << endmsg;
1639 } else if (_click_io) {
1640 setup_click_state (&node);
1643 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1644 ControlProtocolManager::instance().set_state (*child, version);
1647 if ((child = find_named_node (node, "Script"))) {
1648 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1649 if (!(*n)->is_content ()) { continue; }
1651 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1653 Glib::Threads::Mutex::Lock lm (lua_lock);
1654 (*_lua_load)(std::string ((const char*)buf, size));
1655 } catch (luabridge::LuaException const& e) {
1656 cerr << "LuaException:" << e.what () << endl;
1662 update_route_record_state ();
1664 /* here beginneth the second phase ... */
1665 set_snapshot_name (_current_snapshot_name);
1667 StateReady (); /* EMIT SIGNAL */
1680 Session::load_routes (const XMLNode& node, int version)
1683 XMLNodeConstIterator niter;
1684 RouteList new_routes;
1686 nlist = node.children();
1690 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1692 boost::shared_ptr<Route> route;
1693 if (version < 3000) {
1694 route = XMLRouteFactory_2X (**niter, version);
1696 route = XMLRouteFactory (**niter, version);
1700 error << _("Session: cannot create Route from XML description.") << endmsg;
1704 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1706 new_routes.push_back (route);
1709 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1711 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1713 BootMessage (_("Finished adding tracks/busses"));
1718 boost::shared_ptr<Route>
1719 Session::XMLRouteFactory (const XMLNode& node, int version)
1721 boost::shared_ptr<Route> ret;
1723 if (node.name() != "Route") {
1727 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1729 DataType type = DataType::AUDIO;
1730 XMLProperty const * prop = node.property("default-type");
1733 type = DataType (prop->value());
1736 assert (type != DataType::NIL);
1740 boost::shared_ptr<Track> track;
1742 if (type == DataType::AUDIO) {
1743 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1745 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1748 if (track->init()) {
1752 if (track->set_state (node, version)) {
1756 BOOST_MARK_TRACK (track);
1760 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1761 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1763 if (r->init () == 0 && r->set_state (node, version) == 0) {
1764 BOOST_MARK_ROUTE (r);
1772 boost::shared_ptr<Route>
1773 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1775 boost::shared_ptr<Route> ret;
1777 if (node.name() != "Route") {
1781 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1783 ds_prop = node.property (X_("diskstream"));
1786 DataType type = DataType::AUDIO;
1787 XMLProperty const * prop = node.property("default-type");
1790 type = DataType (prop->value());
1793 assert (type != DataType::NIL);
1797 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1798 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1802 if (i == _diskstreams_2X.end()) {
1803 error << _("Could not find diskstream for route") << endmsg;
1804 return boost::shared_ptr<Route> ();
1807 boost::shared_ptr<Track> track;
1809 if (type == DataType::AUDIO) {
1810 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1812 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1815 if (track->init()) {
1819 if (track->set_state (node, version)) {
1823 track->set_diskstream (*i);
1825 BOOST_MARK_TRACK (track);
1829 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1830 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1832 if (r->init () == 0 && r->set_state (node, version) == 0) {
1833 BOOST_MARK_ROUTE (r);
1842 Session::load_regions (const XMLNode& node)
1845 XMLNodeConstIterator niter;
1846 boost::shared_ptr<Region> region;
1848 nlist = node.children();
1852 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1853 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1854 error << _("Session: cannot create Region from XML description.");
1855 XMLProperty const * name = (**niter).property("name");
1858 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1869 Session::load_compounds (const XMLNode& node)
1871 XMLNodeList calist = node.children();
1872 XMLNodeConstIterator caiter;
1873 XMLProperty const * caprop;
1875 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1876 XMLNode* ca = *caiter;
1880 if ((caprop = ca->property (X_("original"))) == 0) {
1883 orig_id = caprop->value();
1885 if ((caprop = ca->property (X_("copy"))) == 0) {
1888 copy_id = caprop->value();
1890 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1891 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1893 if (!orig || !copy) {
1894 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1900 RegionFactory::add_compound_association (orig, copy);
1907 Session::load_nested_sources (const XMLNode& node)
1910 XMLNodeConstIterator niter;
1912 nlist = node.children();
1914 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1915 if ((*niter)->name() == "Source") {
1917 /* it may already exist, so don't recreate it unnecessarily
1920 XMLProperty const * prop = (*niter)->property (X_("id"));
1922 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1926 ID source_id (prop->value());
1928 if (!source_by_id (source_id)) {
1931 SourceFactory::create (*this, **niter, true);
1933 catch (failed_constructor& err) {
1934 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1941 boost::shared_ptr<Region>
1942 Session::XMLRegionFactory (const XMLNode& node, bool full)
1944 XMLProperty const * type = node.property("type");
1948 const XMLNodeList& nlist = node.children();
1950 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1951 XMLNode *child = (*niter);
1952 if (child->name() == "NestedSource") {
1953 load_nested_sources (*child);
1957 if (!type || type->value() == "audio") {
1958 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1959 } else if (type->value() == "midi") {
1960 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1963 } catch (failed_constructor& err) {
1964 return boost::shared_ptr<Region> ();
1967 return boost::shared_ptr<Region> ();
1970 boost::shared_ptr<AudioRegion>
1971 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1973 XMLProperty const * prop;
1974 boost::shared_ptr<Source> source;
1975 boost::shared_ptr<AudioSource> as;
1977 SourceList master_sources;
1978 uint32_t nchans = 1;
1981 if (node.name() != X_("Region")) {
1982 return boost::shared_ptr<AudioRegion>();
1985 if ((prop = node.property (X_("channels"))) != 0) {
1986 nchans = atoi (prop->value().c_str());
1989 if ((prop = node.property ("name")) == 0) {
1990 cerr << "no name for this region\n";
1994 if ((prop = node.property (X_("source-0"))) == 0) {
1995 if ((prop = node.property ("source")) == 0) {
1996 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1997 return boost::shared_ptr<AudioRegion>();
2001 PBD::ID s_id (prop->value());
2003 if ((source = source_by_id (s_id)) == 0) {
2004 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2005 return boost::shared_ptr<AudioRegion>();
2008 as = boost::dynamic_pointer_cast<AudioSource>(source);
2010 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2011 return boost::shared_ptr<AudioRegion>();
2014 sources.push_back (as);
2016 /* pickup other channels */
2018 for (uint32_t n=1; n < nchans; ++n) {
2019 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2020 if ((prop = node.property (buf)) != 0) {
2022 PBD::ID id2 (prop->value());
2024 if ((source = source_by_id (id2)) == 0) {
2025 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2026 return boost::shared_ptr<AudioRegion>();
2029 as = boost::dynamic_pointer_cast<AudioSource>(source);
2031 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2032 return boost::shared_ptr<AudioRegion>();
2034 sources.push_back (as);
2038 for (uint32_t n = 0; n < nchans; ++n) {
2039 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2040 if ((prop = node.property (buf)) != 0) {
2042 PBD::ID id2 (prop->value());
2044 if ((source = source_by_id (id2)) == 0) {
2045 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2046 return boost::shared_ptr<AudioRegion>();
2049 as = boost::dynamic_pointer_cast<AudioSource>(source);
2051 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2052 return boost::shared_ptr<AudioRegion>();
2054 master_sources.push_back (as);
2059 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2061 /* a final detail: this is the one and only place that we know how long missing files are */
2063 if (region->whole_file()) {
2064 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2065 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2067 sfp->set_length (region->length());
2072 if (!master_sources.empty()) {
2073 if (master_sources.size() != nchans) {
2074 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2076 region->set_master_sources (master_sources);
2084 catch (failed_constructor& err) {
2085 return boost::shared_ptr<AudioRegion>();
2089 boost::shared_ptr<MidiRegion>
2090 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2092 XMLProperty const * prop;
2093 boost::shared_ptr<Source> source;
2094 boost::shared_ptr<MidiSource> ms;
2097 if (node.name() != X_("Region")) {
2098 return boost::shared_ptr<MidiRegion>();
2101 if ((prop = node.property ("name")) == 0) {
2102 cerr << "no name for this region\n";
2106 if ((prop = node.property (X_("source-0"))) == 0) {
2107 if ((prop = node.property ("source")) == 0) {
2108 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2109 return boost::shared_ptr<MidiRegion>();
2113 PBD::ID s_id (prop->value());
2115 if ((source = source_by_id (s_id)) == 0) {
2116 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2117 return boost::shared_ptr<MidiRegion>();
2120 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2122 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2123 return boost::shared_ptr<MidiRegion>();
2126 sources.push_back (ms);
2129 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2130 /* a final detail: this is the one and only place that we know how long missing files are */
2132 if (region->whole_file()) {
2133 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2134 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2136 sfp->set_length (region->length());
2144 catch (failed_constructor& err) {
2145 return boost::shared_ptr<MidiRegion>();
2150 Session::get_sources_as_xml ()
2153 XMLNode* node = new XMLNode (X_("Sources"));
2154 Glib::Threads::Mutex::Lock lm (source_lock);
2156 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2157 node->add_child_nocopy (i->second->get_state());
2164 Session::reset_write_sources (bool mark_write_complete, bool force)
2166 boost::shared_ptr<RouteList> rl = routes.reader();
2167 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2168 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2170 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2171 tr->reset_write_sources(mark_write_complete, force);
2172 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2178 Session::load_sources (const XMLNode& node)
2181 XMLNodeConstIterator niter;
2182 boost::shared_ptr<Source> source; /* don't need this but it stops some
2183 * versions of gcc complaining about
2184 * discarded return values.
2187 nlist = node.children();
2191 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2192 #ifdef PLATFORM_WINDOWS
2198 #ifdef PLATFORM_WINDOWS
2199 // do not show "insert media" popups (files embedded from removable media).
2200 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2202 if ((source = XMLSourceFactory (**niter)) == 0) {
2203 error << _("Session: cannot create Source from XML description.") << endmsg;
2205 #ifdef PLATFORM_WINDOWS
2206 SetErrorMode(old_mode);
2209 } catch (MissingSource& err) {
2210 #ifdef PLATFORM_WINDOWS
2211 SetErrorMode(old_mode);
2216 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2217 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2218 PROGRAM_NAME) << endmsg;
2222 if (!no_questions_about_missing_files) {
2223 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2228 switch (user_choice) {
2230 /* user added a new search location, so try again */
2235 /* user asked to quit the entire session load
2240 no_questions_about_missing_files = true;
2244 no_questions_about_missing_files = true;
2251 case DataType::AUDIO:
2252 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2255 case DataType::MIDI:
2256 /* The MIDI file is actually missing so
2257 * just create a new one in the same
2258 * location. Do not announce its
2262 if (!Glib::path_is_absolute (err.path)) {
2263 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2265 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2270 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2271 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2272 /* reset ID to match the missing one */
2273 source->set_id (**niter);
2274 /* Now we can announce it */
2275 SourceFactory::SourceCreated (source);
2286 boost::shared_ptr<Source>
2287 Session::XMLSourceFactory (const XMLNode& node)
2289 if (node.name() != "Source") {
2290 return boost::shared_ptr<Source>();
2294 /* note: do peak building in another thread when loading session state */
2295 return SourceFactory::create (*this, node, true);
2298 catch (failed_constructor& err) {
2299 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2300 return boost::shared_ptr<Source>();
2305 Session::save_template (string template_name, bool replace_existing)
2307 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2311 bool absolute_path = Glib::path_is_absolute (template_name);
2313 /* directory to put the template in */
2314 std::string template_dir_path;
2316 if (!absolute_path) {
2317 std::string user_template_dir(user_template_directory());
2319 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2320 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2321 user_template_dir, g_strerror (errno)) << endmsg;
2325 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2327 template_dir_path = template_name;
2330 if (!ARDOUR::Profile->get_trx()) {
2331 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2332 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2333 template_dir_path) << endmsg;
2337 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2338 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2339 template_dir_path, g_strerror (errno)) << endmsg;
2345 std::string template_file_path;
2347 if (ARDOUR::Profile->get_trx()) {
2348 template_file_path = template_name;
2350 if (absolute_path) {
2351 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2353 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2357 SessionSaveUnderway (); /* EMIT SIGNAL */
2362 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2363 tree.set_root (&get_template());
2366 if (!tree.write (template_file_path)) {
2367 error << _("template not saved") << endmsg;
2371 store_recent_templates (template_file_path);
2377 Session::refresh_disk_space ()
2379 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2381 Glib::Threads::Mutex::Lock lm (space_lock);
2383 /* get freespace on every FS that is part of the session path */
2385 _total_free_4k_blocks = 0;
2386 _total_free_4k_blocks_uncertain = false;
2388 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2389 #if defined(__NetBSD__)
2390 struct statvfs statfsbuf;
2392 statvfs (i->path.c_str(), &statfsbuf);
2394 struct statfs statfsbuf;
2396 statfs (i->path.c_str(), &statfsbuf);
2398 double const scale = statfsbuf.f_bsize / 4096.0;
2400 /* See if this filesystem is read-only */
2401 struct statvfs statvfsbuf;
2402 statvfs (i->path.c_str(), &statvfsbuf);
2404 /* f_bavail can be 0 if it is undefined for whatever
2405 filesystem we are looking at; Samba shares mounted
2406 via GVFS are an example of this.
2408 if (statfsbuf.f_bavail == 0) {
2409 /* block count unknown */
2411 i->blocks_unknown = true;
2412 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2413 /* read-only filesystem */
2415 i->blocks_unknown = false;
2417 /* read/write filesystem with known space */
2418 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2419 i->blocks_unknown = false;
2422 _total_free_4k_blocks += i->blocks;
2423 if (i->blocks_unknown) {
2424 _total_free_4k_blocks_uncertain = true;
2427 #elif defined PLATFORM_WINDOWS
2428 vector<string> scanned_volumes;
2429 vector<string>::iterator j;
2430 vector<space_and_path>::iterator i;
2431 DWORD nSectorsPerCluster, nBytesPerSector,
2432 nFreeClusters, nTotalClusters;
2436 _total_free_4k_blocks = 0;
2438 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2439 strncpy (disk_drive, (*i).path.c_str(), 3);
2443 volume_found = false;
2444 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2446 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2447 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2448 i->blocks = (uint32_t)(nFreeBytes / 4096);
2450 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2451 if (0 == j->compare(disk_drive)) {
2452 volume_found = true;
2457 if (!volume_found) {
2458 scanned_volumes.push_back(disk_drive);
2459 _total_free_4k_blocks += i->blocks;
2464 if (0 == _total_free_4k_blocks) {
2465 strncpy (disk_drive, path().c_str(), 3);
2468 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2470 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2471 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2472 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2479 Session::get_best_session_directory_for_new_audio ()
2481 vector<space_and_path>::iterator i;
2482 string result = _session_dir->root_path();
2484 /* handle common case without system calls */
2486 if (session_dirs.size() == 1) {
2490 /* OK, here's the algorithm we're following here:
2492 We want to select which directory to use for
2493 the next file source to be created. Ideally,
2494 we'd like to use a round-robin process so as to
2495 get maximum performance benefits from splitting
2496 the files across multiple disks.
2498 However, in situations without much diskspace, an
2499 RR approach may end up filling up a filesystem
2500 with new files while others still have space.
2501 Its therefore important to pay some attention to
2502 the freespace in the filesystem holding each
2503 directory as well. However, if we did that by
2504 itself, we'd keep creating new files in the file
2505 system with the most space until it was as full
2506 as all others, thus negating any performance
2507 benefits of this RAID-1 like approach.
2509 So, we use a user-configurable space threshold. If
2510 there are at least 2 filesystems with more than this
2511 much space available, we use RR selection between them.
2512 If not, then we pick the filesystem with the most space.
2514 This gets a good balance between the two
2518 refresh_disk_space ();
2520 int free_enough = 0;
2522 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2523 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2528 if (free_enough >= 2) {
2529 /* use RR selection process, ensuring that the one
2533 i = last_rr_session_dir;
2536 if (++i == session_dirs.end()) {
2537 i = session_dirs.begin();
2540 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2541 SessionDirectory sdir(i->path);
2542 if (sdir.create ()) {
2544 last_rr_session_dir = i;
2549 } while (i != last_rr_session_dir);
2553 /* pick FS with the most freespace (and that
2554 seems to actually work ...)
2557 vector<space_and_path> sorted;
2558 space_and_path_ascending_cmp cmp;
2560 sorted = session_dirs;
2561 sort (sorted.begin(), sorted.end(), cmp);
2563 for (i = sorted.begin(); i != sorted.end(); ++i) {
2564 SessionDirectory sdir(i->path);
2565 if (sdir.create ()) {
2567 last_rr_session_dir = i;
2577 Session::automation_dir () const
2579 return Glib::build_filename (_path, automation_dir_name);
2583 Session::analysis_dir () const
2585 return Glib::build_filename (_path, analysis_dir_name);
2589 Session::plugins_dir () const
2591 return Glib::build_filename (_path, plugins_dir_name);
2595 Session::externals_dir () const
2597 return Glib::build_filename (_path, externals_dir_name);
2601 Session::load_bundles (XMLNode const & node)
2603 XMLNodeList nlist = node.children();
2604 XMLNodeConstIterator niter;
2608 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2609 if ((*niter)->name() == "InputBundle") {
2610 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2611 } else if ((*niter)->name() == "OutputBundle") {
2612 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2614 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2623 Session::load_route_groups (const XMLNode& node, int version)
2625 XMLNodeList nlist = node.children();
2626 XMLNodeConstIterator niter;
2630 if (version >= 3000) {
2632 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2633 if ((*niter)->name() == "RouteGroup") {
2634 RouteGroup* rg = new RouteGroup (*this, "");
2635 add_route_group (rg);
2636 rg->set_state (**niter, version);
2640 } else if (version < 3000) {
2642 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2643 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2644 RouteGroup* rg = new RouteGroup (*this, "");
2645 add_route_group (rg);
2646 rg->set_state (**niter, version);
2655 state_file_filter (const string &str, void* /*arg*/)
2657 return (str.length() > strlen(statefile_suffix) &&
2658 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2662 remove_end(string state)
2664 string statename(state);
2666 string::size_type start,end;
2667 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2668 statename = statename.substr (start+1);
2671 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2672 end = statename.length();
2675 return string(statename.substr (0, end));
2679 Session::possible_states (string path)
2681 vector<string> states;
2682 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2684 transform(states.begin(), states.end(), states.begin(), remove_end);
2686 sort (states.begin(), states.end());
2692 Session::possible_states () const
2694 return possible_states(_path);
2698 Session::new_route_group (const std::string& name)
2700 RouteGroup* rg = NULL;
2702 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2703 if ((*i)->name () == name) {
2710 rg = new RouteGroup (*this, name);
2711 add_route_group (rg);
2717 Session::add_route_group (RouteGroup* g)
2719 _route_groups.push_back (g);
2720 route_group_added (g); /* EMIT SIGNAL */
2722 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2723 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2724 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2730 Session::remove_route_group (RouteGroup& rg)
2732 list<RouteGroup*>::iterator i;
2734 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2735 _route_groups.erase (i);
2738 route_group_removed (); /* EMIT SIGNAL */
2742 /** Set a new order for our route groups, without adding or removing any.
2743 * @param groups Route group list in the new order.
2746 Session::reorder_route_groups (list<RouteGroup*> groups)
2748 _route_groups = groups;
2750 route_groups_reordered (); /* EMIT SIGNAL */
2756 Session::route_group_by_name (string name)
2758 list<RouteGroup *>::iterator i;
2760 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2761 if ((*i)->name() == name) {
2769 Session::all_route_group() const
2771 return *_all_route_group;
2775 Session::add_commands (vector<Command*> const & cmds)
2777 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2783 Session::add_command (Command* const cmd)
2785 assert (_current_trans);
2786 DEBUG_UNDO_HISTORY (
2787 string_compose ("Current Undo Transaction %1, adding command: %2",
2788 _current_trans->name (),
2790 _current_trans->add_command (cmd);
2793 PBD::StatefulDiffCommand*
2794 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2796 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2802 Session::begin_reversible_command (const string& name)
2804 begin_reversible_command (g_quark_from_string (name.c_str ()));
2807 /** Begin a reversible command using a GQuark to identify it.
2808 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2809 * but there must be as many begin...()s as there are commit...()s.
2812 Session::begin_reversible_command (GQuark q)
2814 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2815 to hold all the commands that are committed. This keeps the order of
2816 commands correct in the history.
2819 if (_current_trans == 0) {
2820 DEBUG_UNDO_HISTORY (string_compose (
2821 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2823 /* start a new transaction */
2824 assert (_current_trans_quarks.empty ());
2825 _current_trans = new UndoTransaction();
2826 _current_trans->set_name (g_quark_to_string (q));
2828 DEBUG_UNDO_HISTORY (
2829 string_compose ("Begin Reversible Command, current transaction: %1",
2830 _current_trans->name ()));
2833 _current_trans_quarks.push_front (q);
2837 Session::abort_reversible_command ()
2839 if (_current_trans != 0) {
2840 DEBUG_UNDO_HISTORY (
2841 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2842 _current_trans->clear();
2843 delete _current_trans;
2845 _current_trans_quarks.clear();
2850 Session::commit_reversible_command (Command *cmd)
2852 assert (_current_trans);
2853 assert (!_current_trans_quarks.empty ());
2858 DEBUG_UNDO_HISTORY (
2859 string_compose ("Current Undo Transaction %1, adding command: %2",
2860 _current_trans->name (),
2862 _current_trans->add_command (cmd);
2865 DEBUG_UNDO_HISTORY (
2866 string_compose ("Commit Reversible Command, current transaction: %1",
2867 _current_trans->name ()));
2869 _current_trans_quarks.pop_front ();
2871 if (!_current_trans_quarks.empty ()) {
2872 DEBUG_UNDO_HISTORY (
2873 string_compose ("Commit Reversible Command, transaction is not "
2874 "top-level, current transaction: %1",
2875 _current_trans->name ()));
2876 /* the transaction we're committing is not the top-level one */
2880 if (_current_trans->empty()) {
2881 /* no commands were added to the transaction, so just get rid of it */
2882 DEBUG_UNDO_HISTORY (
2883 string_compose ("Commit Reversible Command, No commands were "
2884 "added to current transaction: %1",
2885 _current_trans->name ()));
2886 delete _current_trans;
2891 gettimeofday (&now, 0);
2892 _current_trans->set_timestamp (now);
2894 _history.add (_current_trans);
2899 accept_all_audio_files (const string& path, void* /*arg*/)
2901 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2905 if (!AudioFileSource::safe_audio_file_extension (path)) {
2913 accept_all_midi_files (const string& path, void* /*arg*/)
2915 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2919 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2920 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2921 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2925 accept_all_state_files (const string& path, void* /*arg*/)
2927 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2931 std::string const statefile_ext (statefile_suffix);
2932 if (path.length() >= statefile_ext.length()) {
2933 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2940 Session::find_all_sources (string path, set<string>& result)
2945 if (!tree.read (path)) {
2949 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2954 XMLNodeConstIterator niter;
2956 nlist = node->children();
2960 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2962 XMLProperty const * prop;
2964 if ((prop = (*niter)->property (X_("type"))) == 0) {
2968 DataType type (prop->value());
2970 if ((prop = (*niter)->property (X_("name"))) == 0) {
2974 if (Glib::path_is_absolute (prop->value())) {
2975 /* external file, ignore */
2983 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2984 result.insert (found_path);
2992 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2994 vector<string> state_files;
2996 string this_snapshot_path;
3002 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3003 ripped = ripped.substr (0, ripped.length() - 1);
3006 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3008 if (state_files.empty()) {
3013 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3014 this_snapshot_path += statefile_suffix;
3016 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3018 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3020 if (exclude_this_snapshot && *i == this_snapshot_path) {
3021 cerr << "\texcluded\n";
3026 if (find_all_sources (*i, result) < 0) {
3034 struct RegionCounter {
3035 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3036 AudioSourceList::iterator iter;
3037 boost::shared_ptr<Region> region;
3040 RegionCounter() : count (0) {}
3044 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3046 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3047 return r.get_value_or (1);
3051 Session::cleanup_regions ()
3053 bool removed = false;
3054 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3056 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3058 uint32_t used = playlists->region_use_count (i->second);
3060 if (used == 0 && !i->second->automatic ()) {
3061 boost::weak_ptr<Region> w = i->second;
3064 RegionFactory::map_remove (w);
3071 // re-check to remove parent references of compound regions
3072 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3073 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3077 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3078 if (0 == playlists->region_use_count (i->second)) {
3079 boost::weak_ptr<Region> w = i->second;
3081 RegionFactory::map_remove (w);
3088 /* dump the history list */
3095 Session::can_cleanup_peakfiles () const
3097 if (deletion_in_progress()) {
3100 if (!_writable || (_state_of_the_state & CannotSave)) {
3101 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3104 if (record_status() == Recording) {
3105 error << _("Cannot cleanup peak-files while recording") << endmsg;
3112 Session::cleanup_peakfiles ()
3114 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3119 assert (can_cleanup_peakfiles ());
3120 assert (!peaks_cleanup_in_progres());
3122 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3124 int timeout = 5000; // 5 seconds
3125 while (!SourceFactory::files_with_peaks.empty()) {
3126 Glib::usleep (1000);
3127 if (--timeout < 0) {
3128 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3129 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3134 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3135 boost::shared_ptr<AudioSource> as;
3136 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3137 as->close_peakfile();
3141 PBD::clear_directory (session_directory().peak_path());
3143 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3145 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3146 boost::shared_ptr<AudioSource> as;
3147 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3148 SourceFactory::setup_peakfile(as, true);
3155 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3157 pl->deep_sources (*all_sources);
3161 Session::cleanup_sources (CleanupReport& rep)
3163 // FIXME: needs adaptation to midi
3165 vector<boost::shared_ptr<Source> > dead_sources;
3168 vector<string> candidates;
3169 vector<string> unused;
3170 set<string> sources_used_by_all_snapshots;
3177 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3179 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3181 /* this is mostly for windows which doesn't allow file
3182 * renaming if the file is in use. But we don't special
3183 * case it because we need to know if this causes
3184 * problems, and the easiest way to notice that is to
3185 * keep it in place for all platforms.
3188 request_stop (false);
3190 _butler->wait_until_finished ();
3192 /* consider deleting all unused playlists */
3194 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3199 /* sync the "all regions" property of each playlist with its current state
3202 playlists->sync_all_regions_with_regions ();
3204 /* find all un-used sources */
3209 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3211 SourceMap::iterator tmp;
3216 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3220 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3221 dead_sources.push_back (i->second);
3222 i->second->drop_references ();
3228 /* build a list of all the possible audio directories for the session */
3230 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3231 SessionDirectory sdir ((*i).path);
3232 asp += sdir.sound_path();
3234 audio_path += asp.to_string();
3237 /* build a list of all the possible midi directories for the session */
3239 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3240 SessionDirectory sdir ((*i).path);
3241 msp += sdir.midi_path();
3243 midi_path += msp.to_string();
3245 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3246 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3248 /* add sources from all other snapshots as "used", but don't use this
3249 snapshot because the state file on disk still references sources we
3250 may have already dropped.
3253 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3255 /* Although the region factory has a list of all regions ever created
3256 * for this session, we're only interested in regions actually in
3257 * playlists right now. So merge all playlist regions lists together.
3259 * This will include the playlists used within compound regions.
3262 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3264 /* add our current source list
3267 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3268 boost::shared_ptr<FileSource> fs;
3269 SourceMap::iterator tmp = i;
3272 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3278 /* this is mostly for windows which doesn't allow file
3279 * renaming if the file is in use. But we do not special
3280 * case it because we need to know if this causes
3281 * problems, and the easiest way to notice that is to
3282 * keep it in place for all platforms.
3287 if (!fs->is_stub()) {
3289 /* Note that we're checking a list of all
3290 * sources across all snapshots with the list
3291 * of sources used by this snapshot.
3294 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3295 /* this source is in use by this snapshot */
3296 sources_used_by_all_snapshots.insert (fs->path());
3297 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3299 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3300 /* this source is NOT in use by this snapshot
3303 /* remove all related regions from RegionFactory master list
3306 RegionFactory::remove_regions_using_source (i->second);
3308 /* remove from our current source list
3309 * also. We may not remove it from
3310 * disk, because it may be used by
3311 * other snapshots, but it isn't used inside this
3312 * snapshot anymore, so we don't need a
3323 /* now check each candidate source to see if it exists in the list of
3324 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3327 cerr << "Candidates: " << candidates.size() << endl;
3328 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3330 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3335 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3337 tmppath1 = canonical_path (spath);
3338 tmppath2 = canonical_path ((*i));
3340 cerr << "\t => " << tmppath2 << endl;
3342 if (tmppath1 == tmppath2) {
3349 unused.push_back (spath);
3353 cerr << "Actually unused: " << unused.size() << endl;
3355 if (unused.empty()) {
3361 /* now try to move all unused files into the "dead" directory(ies) */
3363 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3368 /* don't move the file across filesystems, just
3369 stick it in the `dead_dir_name' directory
3370 on whichever filesystem it was already on.
3373 if ((*x).find ("/sounds/") != string::npos) {
3375 /* old school, go up 1 level */
3377 newpath = Glib::path_get_dirname (*x); // "sounds"
3378 newpath = Glib::path_get_dirname (newpath); // "session-name"
3382 /* new school, go up 4 levels */
3384 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3385 newpath = Glib::path_get_dirname (newpath); // "session-name"
3386 newpath = Glib::path_get_dirname (newpath); // "interchange"
3387 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3390 newpath = Glib::build_filename (newpath, dead_dir_name);
3392 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3393 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3397 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3399 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3401 /* the new path already exists, try versioning */
3403 char buf[PATH_MAX+1];
3407 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3410 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3411 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3415 if (version == 999) {
3416 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3420 newpath = newpath_v;
3425 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3426 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3427 newpath, g_strerror (errno)) << endmsg;
3431 /* see if there an easy to find peakfile for this file, and remove it.
3434 string base = Glib::path_get_basename (*x);
3435 base += "%A"; /* this is what we add for the channel suffix of all native files,
3436 or for the first channel of embedded files. it will miss
3437 some peakfiles for other channels
3439 string peakpath = construct_peak_filepath (base);
3441 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3442 if (::g_unlink (peakpath.c_str ()) != 0) {
3443 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3444 g_strerror (errno)) << endmsg;
3445 /* try to back out */
3446 ::g_rename (newpath.c_str (), _path.c_str ());
3451 rep.paths.push_back (*x);
3452 rep.space += statbuf.st_size;
3455 /* dump the history list */
3459 /* save state so we don't end up a session file
3460 referring to non-existent sources.
3467 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3473 Session::cleanup_trash_sources (CleanupReport& rep)
3475 // FIXME: needs adaptation for MIDI
3477 vector<space_and_path>::iterator i;
3483 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3485 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3487 clear_directory (dead_dir, &rep.space, &rep.paths);
3494 Session::set_dirty ()
3496 /* never mark session dirty during loading */
3498 if (_state_of_the_state & Loading) {
3502 bool was_dirty = dirty();
3504 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3508 DirtyChanged(); /* EMIT SIGNAL */
3514 Session::set_clean ()
3516 bool was_dirty = dirty();
3518 _state_of_the_state = Clean;
3522 DirtyChanged(); /* EMIT SIGNAL */
3527 Session::set_deletion_in_progress ()
3529 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3533 Session::clear_deletion_in_progress ()
3535 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3539 Session::add_controllable (boost::shared_ptr<Controllable> c)
3541 /* this adds a controllable to the list managed by the Session.
3542 this is a subset of those managed by the Controllable class
3543 itself, and represents the only ones whose state will be saved
3544 as part of the session.
3547 Glib::Threads::Mutex::Lock lm (controllables_lock);
3548 controllables.insert (c);
3551 struct null_deleter { void operator()(void const *) const {} };
3554 Session::remove_controllable (Controllable* c)
3556 if (_state_of_the_state & Deletion) {
3560 Glib::Threads::Mutex::Lock lm (controllables_lock);
3562 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3564 if (x != controllables.end()) {
3565 controllables.erase (x);
3569 boost::shared_ptr<Controllable>
3570 Session::controllable_by_id (const PBD::ID& id)
3572 Glib::Threads::Mutex::Lock lm (controllables_lock);
3574 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3575 if ((*i)->id() == id) {
3580 return boost::shared_ptr<Controllable>();
3583 boost::shared_ptr<Controllable>
3584 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3586 boost::shared_ptr<Controllable> c;
3587 boost::shared_ptr<Stripable> s;
3588 boost::shared_ptr<Route> r;
3590 switch (desc.top_level_type()) {
3591 case ControllableDescriptor::NamedRoute:
3593 std::string str = desc.top_level_name();
3595 if (str == "Master" || str == "master") {
3597 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3599 } else if (str == "auditioner") {
3602 s = route_by_name (desc.top_level_name());
3608 case ControllableDescriptor::PresentationOrderRoute:
3609 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3612 case ControllableDescriptor::PresentationOrderTrack:
3613 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3616 case ControllableDescriptor::PresentationOrderBus:
3617 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3620 case ControllableDescriptor::PresentationOrderVCA:
3621 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3624 case ControllableDescriptor::SelectionCount:
3625 s = route_by_selected_count (desc.selection_id());
3633 r = boost::dynamic_pointer_cast<Route> (s);
3635 switch (desc.subtype()) {
3636 case ControllableDescriptor::Gain:
3637 c = s->gain_control ();
3640 case ControllableDescriptor::Trim:
3641 c = s->trim_control ();
3644 case ControllableDescriptor::Solo:
3645 c = s->solo_control();
3648 case ControllableDescriptor::Mute:
3649 c = s->mute_control();
3652 case ControllableDescriptor::Recenable:
3653 c = s->rec_enable_control ();
3656 case ControllableDescriptor::PanDirection:
3657 c = s->pan_azimuth_control();
3660 case ControllableDescriptor::PanWidth:
3661 c = s->pan_width_control();
3664 case ControllableDescriptor::PanElevation:
3665 c = s->pan_elevation_control();
3668 case ControllableDescriptor::Balance:
3669 /* XXX simple pan control */
3672 case ControllableDescriptor::PluginParameter:
3674 uint32_t plugin = desc.target (0);
3675 uint32_t parameter_index = desc.target (1);
3677 /* revert to zero based counting */
3683 if (parameter_index > 0) {
3691 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3694 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3695 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3700 case ControllableDescriptor::SendGain: {
3701 uint32_t send = desc.target (0);
3708 c = r->send_level_controllable (send);
3713 /* relax and return a null pointer */
3721 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3724 Stateful::add_instant_xml (node, _path);
3727 if (write_to_config) {
3728 Config->add_instant_xml (node);
3733 Session::instant_xml (const string& node_name)
3735 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3736 if (get_disable_all_loaded_plugins ()) {
3740 return Stateful::instant_xml (node_name, _path);
3744 Session::save_history (string snapshot_name)
3752 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3753 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3757 if (snapshot_name.empty()) {
3758 snapshot_name = _current_snapshot_name;
3761 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3762 const string backup_filename = history_filename + backup_suffix;
3763 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3764 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3766 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3767 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3768 error << _("could not backup old history file, current history not saved") << endmsg;
3773 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3775 if (!tree.write (xml_path))
3777 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3779 if (g_remove (xml_path.c_str()) != 0) {
3780 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3781 xml_path, g_strerror (errno)) << endmsg;
3783 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3784 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3785 backup_path, g_strerror (errno)) << endmsg;
3795 Session::restore_history (string snapshot_name)
3799 if (snapshot_name.empty()) {
3800 snapshot_name = _current_snapshot_name;
3803 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3804 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3806 info << "Loading history from " << xml_path << endmsg;
3808 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3809 info << string_compose (_("%1: no history file \"%2\" for this session."),
3810 _name, xml_path) << endmsg;
3814 if (!tree.read (xml_path)) {
3815 error << string_compose (_("Could not understand session history file \"%1\""),
3816 xml_path) << endmsg;
3823 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3826 UndoTransaction* ut = new UndoTransaction ();
3829 ut->set_name(t->property("name")->value());
3830 stringstream ss(t->property("tv-sec")->value());
3832 ss.str(t->property("tv-usec")->value());
3834 ut->set_timestamp(tv);
3836 for (XMLNodeConstIterator child_it = t->children().begin();
3837 child_it != t->children().end(); child_it++)
3839 XMLNode *n = *child_it;
3842 if (n->name() == "MementoCommand" ||
3843 n->name() == "MementoUndoCommand" ||
3844 n->name() == "MementoRedoCommand") {
3846 if ((c = memento_command_factory(n))) {
3850 } else if (n->name() == "NoteDiffCommand") {
3851 PBD::ID id (n->property("midi-source")->value());
3852 boost::shared_ptr<MidiSource> midi_source =
3853 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3855 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3857 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3860 } else if (n->name() == "SysExDiffCommand") {
3862 PBD::ID id (n->property("midi-source")->value());
3863 boost::shared_ptr<MidiSource> midi_source =
3864 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3866 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3868 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3871 } else if (n->name() == "PatchChangeDiffCommand") {
3873 PBD::ID id (n->property("midi-source")->value());
3874 boost::shared_ptr<MidiSource> midi_source =
3875 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3877 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3879 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3882 } else if (n->name() == "StatefulDiffCommand") {
3883 if ((c = stateful_diff_command_factory (n))) {
3884 ut->add_command (c);
3887 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3898 Session::config_changed (std::string p, bool ours)
3904 if (p == "seamless-loop") {
3906 } else if (p == "rf-speed") {
3908 } else if (p == "auto-loop") {
3910 } else if (p == "session-monitoring") {
3912 } else if (p == "auto-input") {
3914 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3915 /* auto-input only makes a difference if we're rolling */
3916 set_track_monitor_input_status (!config.get_auto_input());
3919 } else if (p == "punch-in") {
3923 if ((location = _locations->auto_punch_location()) != 0) {
3925 if (config.get_punch_in ()) {
3926 replace_event (SessionEvent::PunchIn, location->start());
3928 remove_event (location->start(), SessionEvent::PunchIn);
3932 } else if (p == "punch-out") {
3936 if ((location = _locations->auto_punch_location()) != 0) {
3938 if (config.get_punch_out()) {
3939 replace_event (SessionEvent::PunchOut, location->end());
3941 clear_events (SessionEvent::PunchOut);
3945 } else if (p == "edit-mode") {
3947 Glib::Threads::Mutex::Lock lm (playlists->lock);
3949 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3950 (*i)->set_edit_mode (Config->get_edit_mode ());
3953 } else if (p == "use-video-sync") {
3955 waiting_for_sync_offset = config.get_use_video_sync();
3957 } else if (p == "mmc-control") {
3959 //poke_midi_thread ();
3961 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3963 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3965 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3967 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3969 } else if (p == "midi-control") {
3971 //poke_midi_thread ();
3973 } else if (p == "raid-path") {
3975 setup_raid_path (config.get_raid_path());
3977 } else if (p == "timecode-format") {
3981 } else if (p == "video-pullup") {
3985 } else if (p == "seamless-loop") {
3987 if (play_loop && transport_rolling()) {
3988 // to reset diskstreams etc
3989 request_play_loop (true);
3992 } else if (p == "rf-speed") {
3994 cumulative_rf_motion = 0;
3997 } else if (p == "click-sound") {
3999 setup_click_sounds (1);
4001 } else if (p == "click-emphasis-sound") {
4003 setup_click_sounds (-1);
4005 } else if (p == "clicking") {
4007 if (Config->get_clicking()) {
4008 if (_click_io && click_data) { // don't require emphasis data
4015 } else if (p == "click-gain") {
4018 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4021 } else if (p == "send-mtc") {
4023 if (Config->get_send_mtc ()) {
4024 /* mark us ready to send */
4025 next_quarter_frame_to_send = 0;
4028 } else if (p == "send-mmc") {
4030 _mmc->enable_send (Config->get_send_mmc ());
4032 } else if (p == "jack-time-master") {
4034 engine().reset_timebase ();
4036 } else if (p == "native-file-header-format") {
4038 if (!first_file_header_format_reset) {
4039 reset_native_file_format ();
4042 first_file_header_format_reset = false;
4044 } else if (p == "native-file-data-format") {
4046 if (!first_file_data_format_reset) {
4047 reset_native_file_format ();
4050 first_file_data_format_reset = false;
4052 } else if (p == "external-sync") {
4053 if (!config.get_external_sync()) {
4054 drop_sync_source ();
4056 switch_to_sync_source (Config->get_sync_source());
4058 } else if (p == "denormal-model") {
4060 } else if (p == "history-depth") {
4061 set_history_depth (Config->get_history_depth());
4062 } else if (p == "remote-model") {
4063 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4066 } else if (p == "initial-program-change") {
4068 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4071 buf[0] = MIDI::program; // channel zero by default
4072 buf[1] = (Config->get_initial_program_change() & 0x7f);
4074 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4076 } else if (p == "solo-mute-override") {
4077 // catch_up_on_solo_mute_override ();
4078 } else if (p == "listen-position" || p == "pfl-position") {
4079 listen_position_changed ();
4080 } else if (p == "solo-control-is-listen-control") {
4081 solo_control_mode_changed ();
4082 } else if (p == "solo-mute-gain") {
4083 _solo_cut_control->Changed (true, Controllable::NoGroup);
4084 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4085 last_timecode_valid = false;
4086 } else if (p == "playback-buffer-seconds") {
4087 AudioSource::allocate_working_buffers (frame_rate());
4088 } else if (p == "ltc-source-port") {
4089 reconnect_ltc_input ();
4090 } else if (p == "ltc-sink-port") {
4091 reconnect_ltc_output ();
4092 } else if (p == "timecode-generator-offset") {
4093 ltc_tx_parse_offset();
4094 } else if (p == "auto-return-target-list") {
4095 follow_playhead_priority ();
4102 Session::set_history_depth (uint32_t d)
4104 _history.set_depth (d);
4108 Session::load_diskstreams_2X (XMLNode const & node, int)
4111 XMLNodeConstIterator citer;
4113 clist = node.children();
4115 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4118 /* diskstreams added automatically by DiskstreamCreated handler */
4119 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4120 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4121 _diskstreams_2X.push_back (dsp);
4123 error << _("Session: unknown diskstream type in XML") << endmsg;
4127 catch (failed_constructor& err) {
4128 error << _("Session: could not load diskstream via XML state") << endmsg;
4136 /** Connect things to the MMC object */
4138 Session::setup_midi_machine_control ()
4140 _mmc = new MIDI::MachineControl;
4142 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4143 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4145 if (!async_out || !async_out) {
4149 /* XXXX argh, passing raw pointers back into libmidi++ */
4151 MIDI::Port* mmc_in = async_in.get();
4152 MIDI::Port* mmc_out = async_out.get();
4154 _mmc->set_ports (mmc_in, mmc_out);
4156 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4157 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4158 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4159 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4160 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4161 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4162 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4163 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4164 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4165 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4166 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4167 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4168 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4170 /* also handle MIDI SPP because its so common */
4172 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4173 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4174 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4177 boost::shared_ptr<Controllable>
4178 Session::solo_cut_control() const
4180 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4181 controls in Ardour that currently get presented to the user in the GUI that require
4182 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4184 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4185 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4189 return _solo_cut_control;
4193 Session::save_snapshot_name (const std::string & n)
4195 /* assure Stateful::_instant_xml is loaded
4196 * add_instant_xml() only adds to existing data and defaults
4197 * to use an empty Tree otherwise
4199 instant_xml ("LastUsedSnapshot");
4201 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4202 last_used_snapshot->add_property ("name", string(n));
4203 add_instant_xml (*last_used_snapshot, false);
4207 Session::set_snapshot_name (const std::string & n)
4209 _current_snapshot_name = n;
4210 save_snapshot_name (n);
4214 Session::rename (const std::string& new_name)
4216 string legal_name = legalize_for_path (new_name);
4222 string const old_sources_root = _session_dir->sources_root();
4224 if (!_writable || (_state_of_the_state & CannotSave)) {
4225 error << _("Cannot rename read-only session.") << endmsg;
4226 return 0; // don't show "messed up" warning
4228 if (record_status() == Recording) {
4229 error << _("Cannot rename session while recording") << endmsg;
4230 return 0; // don't show "messed up" warning
4233 StateProtector stp (this);
4238 * interchange subdirectory
4242 * Backup files are left unchanged and not renamed.
4245 /* Windows requires that we close all files before attempting the
4246 * rename. This works on other platforms, but isn't necessary there.
4247 * Leave it in place for all platforms though, since it may help
4248 * catch issues that could arise if the way Source files work ever
4249 * change (since most developers are not using Windows).
4252 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4253 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4259 /* pass one: not 100% safe check that the new directory names don't
4263 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4267 /* this is a stupid hack because Glib::path_get_dirname() is
4268 * lexical-only, and so passing it /a/b/c/ gives a different
4269 * result than passing it /a/b/c ...
4272 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4273 oldstr = oldstr.substr (0, oldstr.length() - 1);
4276 string base = Glib::path_get_dirname (oldstr);
4278 newstr = Glib::build_filename (base, legal_name);
4280 cerr << "Looking for " << newstr << endl;
4282 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4283 cerr << " exists\n";
4292 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4298 /* this is a stupid hack because Glib::path_get_dirname() is
4299 * lexical-only, and so passing it /a/b/c/ gives a different
4300 * result than passing it /a/b/c ...
4303 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4304 oldstr = oldstr.substr (0, oldstr.length() - 1);
4307 string base = Glib::path_get_dirname (oldstr);
4308 newstr = Glib::build_filename (base, legal_name);
4310 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4312 cerr << "Rename " << oldstr << " => " << newstr << endl;
4313 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4314 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4315 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4319 /* Reset path in "session dirs" */
4324 /* reset primary SessionDirectory object */
4327 (*_session_dir) = newstr;
4332 /* now rename directory below session_dir/interchange */
4334 string old_interchange_dir;
4335 string new_interchange_dir;
4337 /* use newstr here because we renamed the path
4338 * (folder/directory) that used to be oldstr to newstr above
4341 v.push_back (newstr);
4342 v.push_back (interchange_dir_name);
4343 v.push_back (Glib::path_get_basename (oldstr));
4345 old_interchange_dir = Glib::build_filename (v);
4348 v.push_back (newstr);
4349 v.push_back (interchange_dir_name);
4350 v.push_back (legal_name);
4352 new_interchange_dir = Glib::build_filename (v);
4354 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4356 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4357 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4358 old_interchange_dir, new_interchange_dir,
4361 error << string_compose (_("renaming %s as %2 failed (%3)"),
4362 old_interchange_dir, new_interchange_dir,
4371 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4372 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4374 cerr << "Rename " << oldstr << " => " << newstr << endl;
4376 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4377 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4378 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4384 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4386 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4387 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4389 cerr << "Rename " << oldstr << " => " << newstr << endl;
4391 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4392 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4393 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4398 /* remove old name from recent sessions */
4399 remove_recent_sessions (_path);
4402 /* update file source paths */
4404 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4405 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4407 string p = fs->path ();
4408 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4410 SourceFactory::setup_peakfile(i->second, true);
4414 set_snapshot_name (new_name);
4419 /* save state again to get everything just right */
4421 save_state (_current_snapshot_name);
4423 /* add to recent sessions */
4425 store_recent_sessions (new_name, _path);
4431 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4433 bool found_sr = false;
4434 bool found_data_format = false;
4436 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4440 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4444 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4447 xmlFreeParserCtxt(ctxt);
4451 xmlNodePtr node = xmlDocGetRootElement(doc);
4454 xmlFreeParserCtxt(ctxt);
4462 for (attr = node->properties; attr; attr = attr->next) {
4463 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4464 sample_rate = atoi ((char*)attr->children->content);
4469 node = node->children;
4470 while (node != NULL) {
4471 if (strcmp((const char*) node->name, "Config")) {
4475 for (node = node->children; node; node = node->next) {
4476 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4477 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4479 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4481 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4483 found_data_format = true;
4493 xmlFreeParserCtxt(ctxt);
4496 return !(found_sr && found_data_format); // zero if they are both found
4500 Session::get_snapshot_from_instant (const std::string& session_dir)
4502 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4504 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4509 if (!tree.read (instant_xml_path)) {
4513 XMLProperty const * prop;
4514 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4515 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4516 return prop->value();
4522 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4523 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4526 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4530 SourcePathMap source_path_map;
4532 boost::shared_ptr<AudioFileSource> afs;
4537 Glib::Threads::Mutex::Lock lm (source_lock);
4539 cerr << " total sources = " << sources.size();
4541 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4542 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4548 if (fs->within_session()) {
4552 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4553 source_path_map[fs->path()].push_back (fs);
4555 SeveralFileSources v;
4557 source_path_map.insert (make_pair (fs->path(), v));
4563 cerr << " fsources = " << total << endl;
4565 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4567 /* tell caller where we are */
4569 string old_path = i->first;
4571 callback (n, total, old_path);
4573 cerr << old_path << endl;
4577 switch (i->second.front()->type()) {
4578 case DataType::AUDIO:
4579 new_path = new_audio_source_path_for_embedded (old_path);
4582 case DataType::MIDI:
4583 /* XXX not implemented yet */
4587 if (new_path.empty()) {
4591 cerr << "Move " << old_path << " => " << new_path << endl;
4593 if (!copy_file (old_path, new_path)) {
4594 cerr << "failed !\n";
4598 /* make sure we stop looking in the external
4599 dir/folder. Remember, this is an all-or-nothing
4600 operations, it doesn't merge just some files.
4602 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4604 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4605 (*f)->set_path (new_path);
4610 save_state ("", false, false);
4616 bool accept_all_files (string const &, void *)
4622 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4624 /* 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.
4629 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4631 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4633 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4635 v.push_back (new_session_folder); /* full path */
4636 v.push_back (interchange_dir_name);
4637 v.push_back (new_session_path); /* just one directory/folder */
4638 v.push_back (typedir);
4639 v.push_back (Glib::path_get_basename (old_path));
4641 return Glib::build_filename (v);
4645 Session::save_as (SaveAs& saveas)
4647 vector<string> files;
4648 string current_folder = Glib::path_get_dirname (_path);
4649 string new_folder = legalize_for_path (saveas.new_name);
4650 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4651 int64_t total_bytes = 0;
4655 int32_t internal_file_cnt = 0;
4657 vector<string> do_not_copy_extensions;
4658 do_not_copy_extensions.push_back (statefile_suffix);
4659 do_not_copy_extensions.push_back (pending_suffix);
4660 do_not_copy_extensions.push_back (backup_suffix);
4661 do_not_copy_extensions.push_back (temp_suffix);
4662 do_not_copy_extensions.push_back (history_suffix);
4664 /* get total size */
4666 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4668 /* need to clear this because
4669 * find_files_matching_filter() is cumulative
4674 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4676 all += files.size();
4678 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4680 g_stat ((*i).c_str(), &gsb);
4681 total_bytes += gsb.st_size;
4685 /* save old values so we can switch back if we are not switching to the new session */
4687 string old_path = _path;
4688 string old_name = _name;
4689 string old_snapshot = _current_snapshot_name;
4690 string old_sd = _session_dir->root_path();
4691 vector<string> old_search_path[DataType::num_types];
4692 string old_config_search_path[DataType::num_types];
4694 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4695 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4696 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4697 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4699 /* switch session directory */
4701 (*_session_dir) = to_dir;
4703 /* create new tree */
4705 if (!_session_dir->create()) {
4706 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4711 /* copy all relevant files. Find each location in session_dirs,
4712 * and copy files from there to target.
4715 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4717 /* need to clear this because
4718 * find_files_matching_filter() is cumulative
4723 const size_t prefix_len = (*sd).path.size();
4725 /* Work just on the files within this session dir */
4727 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4729 /* add dir separator to protect against collisions with
4730 * track names (e.g. track named "audiofiles" or
4734 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4735 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4736 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4738 /* copy all the files. Handling is different for media files
4739 than others because of the *silly* subtree we have below the interchange
4740 folder. That really was a bad idea, but I'm not fixing it as part of
4741 implementing ::save_as().
4744 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4746 std::string from = *i;
4749 string filename = Glib::path_get_basename (from);
4750 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4751 if (filename == ".DS_STORE") {
4756 if (from.find (audiofile_dir_string) != string::npos) {
4758 /* audio file: only copy if asked */
4760 if (saveas.include_media && saveas.copy_media) {
4762 string to = make_new_media_path (*i, to_dir, new_folder);
4764 info << "media file copying from " << from << " to " << to << endmsg;
4766 if (!copy_file (from, to)) {
4767 throw Glib::FileError (Glib::FileError::IO_ERROR,
4768 string_compose(_("\ncopying \"%1\" failed !"), from));
4772 /* we found media files inside the session folder */
4774 internal_file_cnt++;
4776 } else if (from.find (midifile_dir_string) != string::npos) {
4778 /* midi file: always copy unless
4779 * creating an empty new session
4782 if (saveas.include_media) {
4784 string to = make_new_media_path (*i, to_dir, new_folder);
4786 info << "media file copying from " << from << " to " << to << endmsg;
4788 if (!copy_file (from, to)) {
4789 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4793 /* we found media files inside the session folder */
4795 internal_file_cnt++;
4797 } else if (from.find (analysis_dir_string) != string::npos) {
4799 /* make sure analysis dir exists in
4800 * new session folder, but we're not
4801 * copying analysis files here, see
4805 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4810 /* normal non-media file. Don't copy state, history, etc.
4813 bool do_copy = true;
4815 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4816 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4817 /* end of filename matches extension, do not copy file */
4823 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4824 /* don't copy peakfiles if
4825 * we're not copying media
4831 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4833 info << "attempting to make directory/folder " << to << endmsg;
4835 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4836 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4839 info << "attempting to copy " << from << " to " << to << endmsg;
4841 if (!copy_file (from, to)) {
4842 throw Glib::FileError (Glib::FileError::IO_ERROR,
4843 string_compose(_("\ncopying \"%1\" failed !"), from));
4848 /* measure file size even if we're not going to copy so that our Progress
4849 signals are correct, since we included these do-not-copy files
4850 in the computation of the total size and file count.
4854 g_stat (from.c_str(), &gsb);
4855 copied += gsb.st_size;
4858 double fraction = (double) copied / total_bytes;
4860 bool keep_going = true;
4862 if (saveas.copy_media) {
4864 /* no need or expectation of this if
4865 * media is not being copied, because
4866 * it will be fast(ish).
4869 /* tell someone "X percent, file M of N"; M is one-based */
4871 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4879 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4885 /* copy optional folders, if any */
4887 string old = plugins_dir ();
4888 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4889 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4890 copy_files (old, newdir);
4893 old = externals_dir ();
4894 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4895 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4896 copy_files (old, newdir);
4899 old = automation_dir ();
4900 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4901 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4902 copy_files (old, newdir);
4905 if (saveas.include_media) {
4907 if (saveas.copy_media) {
4908 #ifndef PLATFORM_WINDOWS
4909 /* There are problems with analysis files on
4910 * Windows, because they used a colon in their
4911 * names as late as 4.0. Colons are not legal
4912 * under Windows even if NTFS allows them.
4914 * This is a tricky problem to solve so for
4915 * just don't copy these files. They will be
4916 * regenerated as-needed anyway, subject to the
4917 * existing issue that the filenames will be
4918 * rejected by Windows, which is a separate
4919 * problem (though related).
4922 /* only needed if we are copying media, since the
4923 * analysis data refers to media data
4926 old = analysis_dir ();
4927 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4928 string newdir = Glib::build_filename (to_dir, "analysis");
4929 copy_files (old, newdir);
4931 #endif /* PLATFORM_WINDOWS */
4937 set_snapshot_name (saveas.new_name);
4938 _name = saveas.new_name;
4940 if (saveas.include_media && !saveas.copy_media) {
4942 /* reset search paths of the new session (which we're pretending to be right now) to
4943 include the original session search path, so we can still find all audio.
4946 if (internal_file_cnt) {
4947 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4948 ensure_search_path_includes (*s, DataType::AUDIO);
4949 cerr << "be sure to include " << *s << " for audio" << endl;
4952 /* we do not do this for MIDI because we copy
4953 all MIDI files if saveas.include_media is
4959 bool was_dirty = dirty ();
4961 save_state ("", false, false, !saveas.include_media);
4962 save_default_options ();
4964 if (saveas.copy_media && saveas.copy_external) {
4965 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4966 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4970 saveas.final_session_folder_name = _path;
4972 store_recent_sessions (_name, _path);
4974 if (!saveas.switch_to) {
4976 /* switch back to the way things were */
4980 set_snapshot_name (old_snapshot);
4982 (*_session_dir) = old_sd;
4988 if (internal_file_cnt) {
4989 /* reset these to their original values */
4990 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4991 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4996 /* prune session dirs, and update disk space statistics
5001 session_dirs.clear ();
5002 session_dirs.push_back (sp);
5003 refresh_disk_space ();
5005 /* ensure that all existing tracks reset their current capture source paths
5007 reset_write_sources (true, true);
5009 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5010 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5013 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5014 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5020 if (fs->within_session()) {
5021 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5022 fs->set_path (newpath);
5027 } catch (Glib::FileError& e) {
5029 saveas.failure_message = e.what();
5031 /* recursively remove all the directories */
5033 remove_directory (to_dir);
5041 saveas.failure_message = _("unknown reason");
5043 /* recursively remove all the directories */
5045 remove_directory (to_dir);
5055 static void set_progress (Progress* p, size_t n, size_t t)
5057 p->set_progress (float (n) / float(t));
5061 Session::archive_session (const std::string& dest,
5062 const std::string& name,
5063 ArchiveEncode compress_audio,
5064 bool only_used_sources,
5067 if (dest.empty () || name.empty ()) {
5071 /* save current values */
5072 bool was_dirty = dirty ();
5073 string old_path = _path;
5074 string old_name = _name;
5075 string old_snapshot = _current_snapshot_name;
5076 string old_sd = _session_dir->root_path();
5077 string old_config_search_path[DataType::num_types];
5078 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5079 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5081 /* ensure that session-path is included in search-path */
5083 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5084 if ((*sd).path == old_path) {
5092 /* create temporary dir to save session to */
5093 #ifdef PLATFORM_WINDOWS
5094 char tmp[256] = "C:\\TEMP\\";
5095 GetTempPath (sizeof (tmp), tmp);
5097 char const* tmp = getenv("TMPDIR");
5102 if ((strlen (tmp) + 21) > 1024) {
5107 strcpy (tmptpl, tmp);
5108 strcat (tmptpl, "ardourarchive-XXXXXX");
5109 char* tmpdir = g_mkdtemp (tmptpl);
5115 std::string to_dir = std::string (tmpdir);
5117 /* switch session directory temporarily */
5118 (*_session_dir) = to_dir;
5120 if (!_session_dir->create()) {
5121 (*_session_dir) = old_sd;
5122 remove_directory (to_dir);
5126 /* prepare archive */
5127 string archive = Glib::build_filename (dest, name + ".tar.xz");
5129 PBD::ScopedConnectionList progress_connection;
5130 PBD::FileArchive ar (archive);
5132 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5135 /* collect files to archive */
5136 std::map<string,string> filemap;
5138 vector<string> do_not_copy_extensions;
5139 do_not_copy_extensions.push_back (statefile_suffix);
5140 do_not_copy_extensions.push_back (pending_suffix);
5141 do_not_copy_extensions.push_back (backup_suffix);
5142 do_not_copy_extensions.push_back (temp_suffix);
5143 do_not_copy_extensions.push_back (history_suffix);
5145 vector<string> blacklist_dirs;
5146 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5147 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5148 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5149 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5150 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5151 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5153 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5154 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5156 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5157 if (only_used_sources) {
5158 playlists->sync_all_regions_with_regions ();
5159 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5162 // collect audio sources for this session, calc total size for encoding
5163 // add option to only include *used* sources (see Session::cleanup_sources)
5164 size_t total_size = 0;
5166 Glib::Threads::Mutex::Lock lm (source_lock);
5167 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5168 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5169 if (!afs || afs->readable_length () == 0) {
5173 if (only_used_sources) {
5177 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5182 std::string from = afs->path();
5184 if (compress_audio != NO_ENCODE) {
5185 total_size += afs->readable_length ();
5187 if (afs->within_session()) {
5188 filemap[from] = make_new_media_path (from, name, name);
5190 filemap[from] = make_new_media_path (from, name, name);
5191 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5198 if (compress_audio != NO_ENCODE) {
5200 progress->set_progress (2); // set to "encoding"
5201 progress->set_progress (0);
5204 Glib::Threads::Mutex::Lock lm (source_lock);
5205 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5206 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5207 if (!afs || afs->readable_length () == 0) {
5211 if (only_used_sources) {
5215 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5220 orig_sources[afs] = afs->path();
5221 orig_gain[afs] = afs->gain();
5223 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5224 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5225 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5228 progress->descend ((float)afs->readable_length () / total_size);
5232 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5233 afs->replace_file (new_path);
5234 afs->set_gain (ns->gain(), true);
5237 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5241 progress->ascend ();
5247 progress->set_progress (-1); // set to "archiving"
5248 progress->set_progress (0);
5251 /* index files relevant for this session */
5252 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5253 vector<string> files;
5255 size_t prefix_len = (*sd).path.size();
5256 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5260 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5262 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5263 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5264 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5266 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5267 std::string from = *i;
5270 string filename = Glib::path_get_basename (from);
5271 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5272 if (filename == ".DS_STORE") {
5277 if (from.find (audiofile_dir_string) != string::npos) {
5279 } else if (from.find (midifile_dir_string) != string::npos) {
5280 filemap[from] = make_new_media_path (from, name, name);
5281 } else if (from.find (videofile_dir_string) != string::npos) {
5282 filemap[from] = make_new_media_path (from, name, name);
5284 bool do_copy = true;
5285 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5286 if (from.find (*v) != string::npos) {
5291 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5292 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5299 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5305 /* write session file */
5307 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5309 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5312 save_default_options ();
5314 size_t prefix_len = _path.size();
5315 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5319 /* collect session-state files */
5320 vector<string> files;
5321 do_not_copy_extensions.clear ();
5322 do_not_copy_extensions.push_back (history_suffix);
5324 blacklist_dirs.clear ();
5325 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5327 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5328 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5329 std::string from = *i;
5330 bool do_copy = true;
5331 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5332 if (from.find (*v) != string::npos) {
5337 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5338 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5344 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5348 /* restore original values */
5351 set_snapshot_name (old_snapshot);
5352 (*_session_dir) = old_sd;
5356 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5357 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5359 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5360 i->first->replace_file (i->second);
5362 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5363 i->first->set_gain (i->second, true);
5366 int rv = ar.create (filemap);
5367 remove_directory (to_dir);
5373 Session::undo (uint32_t n)
5375 if (actively_recording()) {
5383 Session::redo (uint32_t n)
5385 if (actively_recording()) {