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"
53 #include "pbd/locale_guard.h"
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/basename.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_archive.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/types_convert.h"
76 #include "pbd/localtime_r.h"
77 #include "pbd/unwind.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_diskstream.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/auditioner.h"
87 #include "ardour/automation_control.h"
88 #include "ardour/boost_debug.h"
89 #include "ardour/butler.h"
90 #include "ardour/controllable_descriptor.h"
91 #include "ardour/control_protocol_manager.h"
92 #include "ardour/directory_names.h"
93 #include "ardour/filename_extensions.h"
94 #include "ardour/graph.h"
95 #include "ardour/location.h"
97 #include "ardour/lv2_plugin.h"
99 #include "ardour/midi_model.h"
100 #include "ardour/midi_patch_manager.h"
101 #include "ardour/midi_region.h"
102 #include "ardour/midi_scene_changer.h"
103 #include "ardour/midi_source.h"
104 #include "ardour/midi_track.h"
105 #include "ardour/pannable.h"
106 #include "ardour/playlist_factory.h"
107 #include "ardour/playlist_source.h"
108 #include "ardour/port.h"
109 #include "ardour/processor.h"
110 #include "ardour/progress.h"
111 #include "ardour/profile.h"
112 #include "ardour/proxy_controllable.h"
113 #include "ardour/recent_sessions.h"
114 #include "ardour/region_factory.h"
115 #include "ardour/revision.h"
116 #include "ardour/route_group.h"
117 #include "ardour/send.h"
118 #include "ardour/selection.h"
119 #include "ardour/session.h"
120 #include "ardour/session_directory.h"
121 #include "ardour/session_metadata.h"
122 #include "ardour/session_playlists.h"
123 #include "ardour/session_state_utils.h"
124 #include "ardour/silentfilesource.h"
125 #include "ardour/smf_source.h"
126 #include "ardour/sndfilesource.h"
127 #include "ardour/source_factory.h"
128 #include "ardour/speakers.h"
129 #include "ardour/template_utils.h"
130 #include "ardour/tempo.h"
131 #include "ardour/ticker.h"
132 #include "ardour/types_convert.h"
133 #include "ardour/user_bundle.h"
134 #include "ardour/vca.h"
135 #include "ardour/vca_manager.h"
137 #include "control_protocol/control_protocol.h"
139 #include "LuaBridge/LuaBridge.h"
141 #include "pbd/i18n.h"
145 using namespace ARDOUR;
148 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
151 Session::pre_engine_init (string fullpath)
153 if (fullpath.empty()) {
155 throw failed_constructor();
158 /* discover canonical fullpath */
160 _path = canonical_path(fullpath);
163 if (Profile->get_trx() ) {
164 // Waves TracksLive has a usecase of session replacement with a new one.
165 // We should check session state file (<session_name>.ardour) existance
166 // to determine if the session is new or not
168 string full_session_name = Glib::build_filename( fullpath, _name );
169 full_session_name += statefile_suffix;
171 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
176 /* finish initialization that can't be done in a normal C++ constructor
180 timerclear (&last_mmc_step);
181 g_atomic_int_set (&processing_prohibited, 0);
182 g_atomic_int_set (&_record_status, Disabled);
183 g_atomic_int_set (&_playback_load, 100);
184 g_atomic_int_set (&_capture_load, 100);
186 _all_route_group->set_active (true, this);
187 interpolation.add_channel_to (0, 0);
189 if (config.get_use_video_sync()) {
190 waiting_for_sync_offset = true;
192 waiting_for_sync_offset = false;
195 last_rr_session_dir = session_dirs.begin();
197 set_history_depth (Config->get_history_depth());
199 /* default: assume simple stereo speaker configuration */
201 _speakers->setup_default_speakers (2);
203 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
204 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
205 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
206 add_controllable (_solo_cut_control);
208 /* These are all static "per-class" signals */
210 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
211 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
212 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
213 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
214 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
216 /* stop IO objects from doing stuff until we're ready for them */
218 Delivery::disable_panners ();
219 IO::disable_connecting ();
223 Session::post_engine_init ()
225 BootMessage (_("Set block size and sample rate"));
227 set_block_size (_engine.samples_per_cycle());
228 set_frame_rate (_engine.sample_rate());
230 BootMessage (_("Using configuration"));
232 _midi_ports = new MidiPortManager;
234 MIDISceneChanger* msc;
236 _scene_changer = msc = new MIDISceneChanger (*this);
237 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
238 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
240 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
241 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
243 setup_midi_machine_control ();
245 if (_butler->start_thread()) {
246 error << _("Butler did not start") << endmsg;
250 if (start_midi_thread ()) {
251 error << _("MIDI I/O thread did not start") << endmsg;
255 setup_click_sounds (0);
256 setup_midi_control ();
258 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
259 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
262 /* tempo map requires sample rate knowledge */
265 _tempo_map = new TempoMap (_current_frame_rate);
266 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
268 } catch (std::exception const & e) {
269 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
272 error << _("Unknown exception during session setup") << endmsg;
277 /* MidiClock requires a tempo map */
280 midi_clock = new MidiClockTicker ();
281 midi_clock->set_session (this);
283 /* crossfades require sample rate knowledge */
285 SndFileSource::setup_standard_crossfades (*this, frame_rate());
286 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
287 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
289 AudioDiskstream::allocate_working_buffers();
290 refresh_disk_space ();
292 /* we're finally ready to call set_state() ... all objects have
293 * been created, the engine is running.
298 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
299 error << _("Could not set session state from XML") << endmsg;
302 } catch (PBD::unknown_enumeration& e) {
303 error << _("Session state: ") << e.what() << endmsg;
307 // set_state() will call setup_raid_path(), but if it's a new session we need
308 // to call setup_raid_path() here.
309 setup_raid_path (_path);
314 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
315 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
317 Config->map_parameters (ff);
318 config.map_parameters (ft);
319 _butler->map_parameters ();
321 /* Reset all panners */
323 Delivery::reset_panners ();
325 /* this will cause the CPM to instantiate any protocols that are in use
326 * (or mandatory), which will pass it this Session, and then call
327 * set_state() on each instantiated protocol to match stored state.
330 ControlProtocolManager::instance().set_session (this);
332 /* This must be done after the ControlProtocolManager set_session above,
333 as it will set states for ports which the ControlProtocolManager creates.
336 // XXX set state of MIDI::Port's
337 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
339 /* And this must be done after the MIDI::Manager::set_port_states as
340 * it will try to make connections whose details are loaded by set_port_states.
345 /* Let control protocols know that we are now all connected, so they
346 * could start talking to surfaces if they want to.
349 ControlProtocolManager::instance().midi_connectivity_established ();
351 if (_is_new && !no_auto_connect()) {
352 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
353 auto_connect_master_bus ();
356 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
358 /* update latencies */
360 initialize_latencies ();
362 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
363 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
364 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
366 } catch (AudioEngine::PortRegistrationFailure& err) {
367 error << err.what() << endmsg;
369 } catch (std::exception const & e) {
370 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
373 error << _("Unknown exception during session setup") << endmsg;
377 BootMessage (_("Reset Remote Controls"));
379 // send_full_time_code (0);
380 _engine.transport_locate (0);
382 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
383 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
385 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
388 /* initial program change will be delivered later; see ::config_changed() */
390 _state_of_the_state = Clean;
392 Port::set_connecting_blocked (false);
394 DirtyChanged (); /* EMIT SIGNAL */
398 } else if (state_was_pending) {
400 remove_pending_capture_state ();
401 state_was_pending = false;
404 /* Now, finally, we can fill the playback buffers */
406 BootMessage (_("Filling playback buffers"));
408 boost::shared_ptr<RouteList> rl = routes.reader();
409 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
410 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
411 if (trk && !trk->hidden()) {
412 trk->seek (_transport_frame, true);
420 Session::session_loaded ()
424 _state_of_the_state = Clean;
426 DirtyChanged (); /* EMIT SIGNAL */
430 } else if (state_was_pending) {
432 remove_pending_capture_state ();
433 state_was_pending = false;
436 /* Now, finally, we can fill the playback buffers */
438 BootMessage (_("Filling playback buffers"));
439 force_locate (_transport_frame, false);
443 Session::raid_path () const
445 Searchpath raid_search_path;
447 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
448 raid_search_path += (*i).path;
451 return raid_search_path.to_string ();
455 Session::setup_raid_path (string path)
464 session_dirs.clear ();
466 Searchpath search_path(path);
467 Searchpath sound_search_path;
468 Searchpath midi_search_path;
470 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
472 sp.blocks = 0; // not needed
473 session_dirs.push_back (sp);
475 SessionDirectory sdir(sp.path);
477 sound_search_path += sdir.sound_path ();
478 midi_search_path += sdir.midi_path ();
481 // reset the round-robin soundfile path thingie
482 last_rr_session_dir = session_dirs.begin();
486 Session::path_is_within_session (const std::string& path)
488 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
489 if (PBD::path_is_within (i->path, path)) {
497 Session::ensure_subdirs ()
501 dir = session_directory().peak_path();
503 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
504 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
508 dir = session_directory().sound_path();
510 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
511 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
515 dir = session_directory().midi_path();
517 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
518 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
522 dir = session_directory().dead_path();
524 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
525 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
529 dir = session_directory().export_path();
531 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
532 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
536 dir = analysis_dir ();
538 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
539 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
543 dir = plugins_dir ();
545 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
546 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
550 dir = externals_dir ();
552 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
553 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
560 /** @param session_template directory containing session template, or empty.
561 * Caller must not hold process lock.
564 Session::create (const string& session_template, BusProfile* bus_profile)
566 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
567 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
571 if (ensure_subdirs ()) {
575 _writable = exists_and_writable (_path);
577 if (!session_template.empty()) {
578 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
580 FILE* in = g_fopen (in_path.c_str(), "rb");
583 /* no need to call legalize_for_path() since the string
584 * in session_template is already a legal path name
586 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
588 FILE* out = g_fopen (out_path.c_str(), "wb");
592 stringstream new_session;
595 size_t charsRead = fread (buf, sizeof(char), 1024, in);
598 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
603 if (charsRead == 0) {
606 new_session.write (buf, charsRead);
610 string file_contents = new_session.str();
611 size_t writeSize = file_contents.length();
612 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
613 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
621 if (!ARDOUR::Profile->get_trx()) {
622 /* Copy plugin state files from template to new session */
623 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
624 copy_recurse (template_plugins, plugins_dir ());
630 error << string_compose (_("Could not open %1 for writing session template"), out_path)
637 error << string_compose (_("Could not open session template %1 for reading"), in_path)
644 if (Profile->get_trx()) {
646 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
647 * Remember that this is a brand new session. Sessions
648 * loaded from saved state will get this range from the saved state.
651 set_session_range_location (0, 0);
653 /* Initial loop location, from absolute zero, length 10 seconds */
655 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
656 _locations->add (loc, true);
657 set_auto_loop_location (loc);
660 _state_of_the_state = Clean;
662 /* set up Master Out and Monitor Out if necessary */
666 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
667 if (bus_profile->master_out_channels) {
668 int rv = add_master_bus (count);
674 if (Config->get_use_monitor_bus())
675 add_monitor_section ();
683 Session::maybe_write_autosave()
685 if (dirty() && record_status() != Recording) {
686 save_state("", true);
691 Session::remove_pending_capture_state ()
693 std::string pending_state_file_path(_session_dir->root_path());
695 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
697 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
699 if (g_remove (pending_state_file_path.c_str()) != 0) {
700 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
701 pending_state_file_path, g_strerror (errno)) << endmsg;
705 /** Rename a state file.
706 * @param old_name Old snapshot name.
707 * @param new_name New snapshot name.
710 Session::rename_state (string old_name, string new_name)
712 if (old_name == _current_snapshot_name || old_name == _name) {
713 /* refuse to rename the current snapshot or the "main" one */
717 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
718 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
720 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
721 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
723 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
724 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
725 old_name, new_name, g_strerror(errno)) << endmsg;
729 /** Remove a state file.
730 * @param snapshot_name Snapshot name.
733 Session::remove_state (string snapshot_name)
735 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
736 // refuse to remove the current snapshot or the "main" one
740 std::string xml_path(_session_dir->root_path());
742 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
744 if (!create_backup_file (xml_path)) {
745 // don't remove it if a backup can't be made
746 // create_backup_file will log the error.
751 if (g_remove (xml_path.c_str()) != 0) {
752 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
753 xml_path, g_strerror (errno)) << endmsg;
757 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
759 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
761 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
764 std::string xml_path(_session_dir->root_path());
766 /* prevent concurrent saves from different threads */
768 Glib::Threads::Mutex::Lock lm (save_state_lock);
770 if (!_writable || (_state_of_the_state & CannotSave)) {
774 if (g_atomic_int_get(&_suspend_save)) {
778 _save_queued = false;
780 snapshot_t fork_state = NormalSave;
781 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
782 /* snapshot, close midi */
783 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
787 const int64_t save_start_time = g_get_monotonic_time();
790 /* tell sources we're saving first, in case they write out to a new file
791 * which should be saved with the state rather than the old one */
792 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
794 i->second->session_saved();
795 } catch (Evoral::SMF::FileError& e) {
796 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
800 SessionSaveUnderway (); /* EMIT SIGNAL */
802 bool mark_as_clean = true;
804 if (!snapshot_name.empty() && !switch_to_snapshot) {
805 mark_as_clean = false;
809 mark_as_clean = false;
810 tree.set_root (&get_template());
812 tree.set_root (&state (true, fork_state));
815 if (snapshot_name.empty()) {
816 snapshot_name = _current_snapshot_name;
817 } else if (switch_to_snapshot) {
818 set_snapshot_name (snapshot_name);
821 assert (!snapshot_name.empty());
825 /* proper save: use statefile_suffix (.ardour in English) */
827 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
829 /* make a backup copy of the old file */
831 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
832 // create_backup_file will log the error
838 /* pending save: use pending_suffix (.pending in English) */
839 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
842 std::string tmp_path(_session_dir->root_path());
843 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
845 cerr << "actually writing state to " << tmp_path << endl;
847 if (!tree.write (tmp_path)) {
848 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
849 if (g_remove (tmp_path.c_str()) != 0) {
850 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
851 tmp_path, g_strerror (errno)) << endmsg;
857 cerr << "renaming state to " << xml_path << endl;
859 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
860 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
861 tmp_path, xml_path, g_strerror(errno)) << endmsg;
862 if (g_remove (tmp_path.c_str()) != 0) {
863 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
864 tmp_path, g_strerror (errno)) << endmsg;
872 save_history (snapshot_name);
875 bool was_dirty = dirty();
877 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
880 DirtyChanged (); /* EMIT SIGNAL */
884 StateSaved (snapshot_name); /* EMIT SIGNAL */
888 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
889 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
895 Session::restore_state (string snapshot_name)
898 if (load_state (snapshot_name) == 0) {
899 set_state (*state_tree->root(), Stateful::loading_state_version);
903 // unknown_enumeration
911 Session::load_state (string snapshot_name)
916 state_was_pending = false;
918 /* check for leftover pending state from a crashed capture attempt */
920 std::string xmlpath(_session_dir->root_path());
921 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
923 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
925 /* there is pending state from a crashed capture attempt */
927 boost::optional<int> r = AskAboutPendingState();
928 if (r.get_value_or (1)) {
929 state_was_pending = true;
933 if (!state_was_pending) {
934 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
937 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
938 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
939 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
945 state_tree = new XMLTree;
949 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
951 if (!state_tree->read (xmlpath)) {
952 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
958 XMLNode const & root (*state_tree->root());
960 if (root.name() != X_("Session")) {
961 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
968 root.get_property ("version", version);
969 Stateful::loading_state_version = parse_stateful_loading_version (version);
971 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
972 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
973 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
976 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
978 std::string backup_path(_session_dir->root_path());
979 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
980 backup_path = Glib::build_filename (backup_path, backup_filename);
982 // only create a backup for a given statefile version once
984 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
986 VersionMismatch (xmlpath, backup_path);
988 if (!copy_file (xmlpath, backup_path)) {;
994 save_snapshot_name (snapshot_name);
1000 Session::load_options (const XMLNode& node)
1002 config.set_variables (node);
1007 Session::save_default_options ()
1009 return config.save_state();
1013 Session::get_state()
1019 Session::get_template()
1021 /* if we don't disable rec-enable, diskstreams
1022 will believe they need to store their capture
1023 sources in their state node.
1026 disable_record (false);
1028 return state(false);
1031 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1032 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1035 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1037 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1040 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1044 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1047 XMLNode* node = new XMLNode("TrackState"); // XXX
1050 PlaylistSet playlists; // SessionPlaylists
1053 // these will work with new_route_from_template()
1054 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1055 child = node->add_child ("Routes");
1056 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1057 if ((*i)->is_auditioner()) {
1060 if ((*i)->is_master() || (*i)->is_monitor()) {
1063 child->add_child_nocopy ((*i)->get_state());
1064 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1066 playlists.insert (track->playlist ());
1070 // on load, Regions in the playlists need to resolve and map Source-IDs
1071 // also playlist needs to be merged or created with new-name..
1072 // ... and Diskstream in tracks adjusted to use the correct playlist
1073 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1074 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1075 child->add_child_nocopy ((*i)->get_state ());
1076 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1077 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1078 const Region::SourceList& sl = (*s)->sources ();
1079 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1080 sources.insert (*sli);
1085 child = node->add_child ("Sources");
1086 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1087 child->add_child_nocopy ((*i)->get_state ());
1088 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1090 #ifdef PLATFORM_WINDOWS
1093 string p = fs->path ();
1094 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1098 std::string sn = Glib::build_filename (path, "share.axml");
1101 tree.set_root (node);
1102 return tree.write (sn.c_str());
1107 struct route_id_compare {
1109 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1111 return r1->id () < r2->id ();
1117 Session::state (bool full_state, snapshot_t snapshot_type)
1120 XMLNode* node = new XMLNode("Session");
1123 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1125 child = node->add_child ("ProgramVersion");
1126 child->set_property("created-with", created_with);
1128 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1129 child->set_property("modified-with", modified_with);
1131 /* store configuration settings */
1135 node->set_property ("name", _name);
1136 node->set_property ("sample-rate", _base_frame_rate);
1138 if (session_dirs.size() > 1) {
1142 vector<space_and_path>::iterator i = session_dirs.begin();
1143 vector<space_and_path>::iterator next;
1145 ++i; /* skip the first one */
1149 while (i != session_dirs.end()) {
1153 if (next != session_dirs.end()) {
1154 p += G_SEARCHPATH_SEPARATOR;
1163 child = node->add_child ("Path");
1164 child->add_content (p);
1166 node->set_property ("end-is-free", _session_range_end_is_free);
1169 /* save the ID counter */
1171 node->set_property ("id-counter", ID::counter());
1173 node->set_property ("name-counter", name_id_counter ());
1175 /* save the event ID counter */
1177 node->set_property ("event-counter", Evoral::event_id_counter());
1179 /* save the VCA counter */
1181 node->set_property ("vca-counter", VCA::get_next_vca_number());
1183 /* various options */
1185 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1186 if (!midi_port_nodes.empty()) {
1187 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1188 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1189 midi_port_stuff->add_child_nocopy (**n);
1191 node->add_child_nocopy (*midi_port_stuff);
1194 XMLNode& cfgxml (config.get_variables ());
1196 /* exclude search-paths from template */
1197 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1198 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1199 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1201 node->add_child_nocopy (cfgxml);
1203 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1205 child = node->add_child ("Sources");
1208 Glib::Threads::Mutex::Lock sl (source_lock);
1210 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1212 /* Don't save information about non-file Sources, or
1213 * about non-destructive file sources that are empty
1214 * and unused by any regions.
1216 boost::shared_ptr<FileSource> fs;
1218 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1222 if (!fs->destructive()) {
1223 if (fs->empty() && !fs->used()) {
1228 if (snapshot_type != NormalSave && fs->within_session ()) {
1229 /* copy MIDI sources to new file
1231 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1232 * because the GUI (midi_region) has a direct pointer to the midi-model
1233 * of the source, as does UndoTransaction.
1235 * On the upside, .mid files are not kept open. The file is only open
1236 * when reading the model initially and when flushing the model to disk:
1237 * source->session_saved () or export.
1239 * We can change the _path of the existing source under the hood, keeping
1240 * all IDs, references and pointers intact.
1242 boost::shared_ptr<SMFSource> ms;
1243 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1244 const std::string ancestor_name = ms->ancestor_name();
1245 const std::string base = PBD::basename_nosuffix(ancestor_name);
1246 const string path = new_midi_source_path (base, false);
1248 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1249 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1250 Source::Lock lm (ms->mutex());
1252 // TODO special-case empty, removable() files: just create a new removable.
1253 // (load + write flushes the model and creates the file)
1255 ms->load_model (lm);
1257 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1258 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1260 if (snapshot_type == SnapshotKeep) {
1261 /* keep working on current session.
1263 * Save snapshot-state with the original filename.
1264 * Switch to use new path for future saves of the main session.
1266 child->add_child_nocopy (ms->get_state());
1270 * ~SMFSource unlinks removable() files.
1272 std::string npath (ms->path ());
1273 ms->replace_file (newsrc->path ());
1274 newsrc->replace_file (npath);
1276 if (snapshot_type == SwitchToSnapshot) {
1277 /* save and switch to snapshot.
1279 * Leave the old file in place (as is).
1280 * Snapshot uses new source directly
1282 child->add_child_nocopy (ms->get_state());
1289 child->add_child_nocopy (siter->second->get_state());
1293 child = node->add_child ("Regions");
1296 Glib::Threads::Mutex::Lock rl (region_lock);
1297 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1298 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1299 boost::shared_ptr<Region> r = i->second;
1300 /* only store regions not attached to playlists */
1301 if (r->playlist() == 0) {
1302 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1303 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1305 child->add_child_nocopy (r->get_state ());
1310 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1312 if (!cassocs.empty()) {
1313 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1315 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1316 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1317 can->set_property (X_("copy"), i->first->id());
1318 can->set_property (X_("original"), i->second->id());
1319 ca->add_child_nocopy (*can);
1326 node->add_child_nocopy (_selection->get_state());
1329 node->add_child_nocopy (_locations->get_state());
1332 Locations loc (*this);
1333 const bool was_dirty = dirty();
1334 // for a template, just create a new Locations, populate it
1335 // with the default start and end, and get the state for that.
1336 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1337 range->set (max_framepos, 0);
1339 XMLNode& locations_state = loc.get_state();
1341 if (ARDOUR::Profile->get_trx() && _locations) {
1342 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1343 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1344 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1345 locations_state.add_child_nocopy ((*i)->get_state ());
1349 node->add_child_nocopy (locations_state);
1351 /* adding a location above will have marked the session
1352 * dirty. This is an artifact, so fix it if the session wasn't
1357 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1361 child = node->add_child ("Bundles");
1363 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1364 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1365 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1367 child->add_child_nocopy (b->get_state());
1372 node->add_child_nocopy (_vca_manager->get_state());
1374 child = node->add_child ("Routes");
1376 boost::shared_ptr<RouteList> r = routes.reader ();
1378 route_id_compare cmp;
1379 RouteList xml_node_order (*r);
1380 xml_node_order.sort (cmp);
1382 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1383 if (!(*i)->is_auditioner()) {
1385 child->add_child_nocopy ((*i)->get_state());
1387 child->add_child_nocopy ((*i)->get_template());
1393 playlists->add_state (node, full_state);
1395 child = node->add_child ("RouteGroups");
1396 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1397 child->add_child_nocopy ((*i)->get_state());
1401 XMLNode* gain_child = node->add_child ("Click");
1402 gain_child->add_child_nocopy (_click_io->state (full_state));
1403 gain_child->add_child_nocopy (_click_gain->state (full_state));
1407 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1408 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1412 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1413 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1416 node->add_child_nocopy (_speakers->get_state());
1417 node->add_child_nocopy (_tempo_map->get_state());
1418 node->add_child_nocopy (get_control_protocol_state());
1421 node->add_child_copy (*_extra_xml);
1425 Glib::Threads::Mutex::Lock lm (lua_lock);
1428 luabridge::LuaRef savedstate ((*_lua_save)());
1429 saved = savedstate.cast<std::string>();
1431 lua.collect_garbage ();
1434 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1435 std::string b64s (b64);
1438 XMLNode* script_node = new XMLNode (X_("Script"));
1439 script_node->set_property (X_("lua"), LUA_VERSION);
1440 script_node->add_content (b64s);
1441 node->add_child_nocopy (*script_node);
1448 Session::get_control_protocol_state ()
1450 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1451 return cpm.get_state();
1455 Session::set_state (const XMLNode& node, int version)
1462 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1464 if (node.name() != X_("Session")) {
1465 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1469 node.get_property ("name", _name);
1471 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1473 _nominal_frame_rate = _base_frame_rate;
1475 assert (AudioEngine::instance()->running ());
1476 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1477 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1478 if (r.get_value_or (0)) {
1484 created_with = "unknown";
1485 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1486 child->get_property (X_("created-with"), created_with);
1489 setup_raid_path(_session_dir->root_path());
1491 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1494 if (node.get_property (X_("id-counter"), counter)) {
1495 ID::init_counter (counter);
1497 /* old sessions used a timebased counter, so fake
1498 * the startup ID counter based on a standard
1503 ID::init_counter (now);
1506 if (node.get_property (X_("name-counter"), counter)) {
1507 init_name_id_counter (counter);
1510 if (node.get_property (X_("event-counter"), counter)) {
1511 Evoral::init_event_id_counter (counter);
1514 if (node.get_property (X_("vca-counter"), counter)) {
1515 VCA::set_next_vca_number (counter);
1517 VCA::set_next_vca_number (1);
1520 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1521 _midi_ports->set_midi_port_states (child->children());
1524 IO::disable_connecting ();
1526 Stateful::save_extra_xml (node);
1528 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1529 load_options (*child);
1530 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1531 load_options (*child);
1533 error << _("Session: XML state has no options section") << endmsg;
1536 if (version >= 3000) {
1537 if ((child = find_named_node (node, "Metadata")) == 0) {
1538 warning << _("Session: XML state has no metadata section") << endmsg;
1539 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1544 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1545 _speakers->set_state (*child, version);
1548 if ((child = find_named_node (node, "Sources")) == 0) {
1549 error << _("Session: XML state has no sources section") << endmsg;
1551 } else if (load_sources (*child)) {
1555 if ((child = find_named_node (node, "TempoMap")) == 0) {
1556 error << _("Session: XML state has no Tempo Map section") << endmsg;
1558 } else if (_tempo_map->set_state (*child, version)) {
1562 if ((child = find_named_node (node, "Locations")) == 0) {
1563 error << _("Session: XML state has no locations section") << endmsg;
1565 } else if (_locations->set_state (*child, version)) {
1569 locations_changed ();
1571 if (_session_range_location) {
1572 AudioFileSource::set_header_position_offset (_session_range_location->start());
1575 if ((child = find_named_node (node, "Regions")) == 0) {
1576 error << _("Session: XML state has no Regions section") << endmsg;
1578 } else if (load_regions (*child)) {
1582 if ((child = find_named_node (node, "Playlists")) == 0) {
1583 error << _("Session: XML state has no playlists section") << endmsg;
1585 } else if (playlists->load (*this, *child)) {
1589 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1591 } else if (playlists->load_unused (*this, *child)) {
1595 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1596 if (load_compounds (*child)) {
1601 if (version >= 3000) {
1602 if ((child = find_named_node (node, "Bundles")) == 0) {
1603 warning << _("Session: XML state has no bundles section") << endmsg;
1606 /* We can't load Bundles yet as they need to be able
1607 * to convert from port names to Port objects, which can't happen until
1609 _bundle_xml_node = new XMLNode (*child);
1613 if (version < 3000) {
1614 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1615 error << _("Session: XML state has no diskstreams section") << endmsg;
1617 } else if (load_diskstreams_2X (*child, version)) {
1622 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1623 _vca_manager->set_state (*child, version);
1626 if ((child = find_named_node (node, "Routes")) == 0) {
1627 error << _("Session: XML state has no routes section") << endmsg;
1629 } else if (load_routes (*child, version)) {
1633 /* Now that we have Routes and masters loaded, connect them if appropriate */
1635 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1637 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1638 _diskstreams_2X.clear ();
1640 if (version >= 3000) {
1642 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1643 error << _("Session: XML state has no route groups section") << endmsg;
1645 } else if (load_route_groups (*child, version)) {
1649 } else if (version < 3000) {
1651 if ((child = find_named_node (node, "EditGroups")) == 0) {
1652 error << _("Session: XML state has no edit groups section") << endmsg;
1654 } else if (load_route_groups (*child, version)) {
1658 if ((child = find_named_node (node, "MixGroups")) == 0) {
1659 error << _("Session: XML state has no mix groups section") << endmsg;
1661 } else if (load_route_groups (*child, version)) {
1666 if ((child = find_named_node (node, "Click")) == 0) {
1667 warning << _("Session: XML state has no click section") << endmsg;
1668 } else if (_click_io) {
1669 setup_click_state (&node);
1672 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1673 ControlProtocolManager::instance().set_state (*child, version);
1676 if ((child = find_named_node (node, "Script"))) {
1677 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1678 if (!(*n)->is_content ()) { continue; }
1680 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1682 Glib::Threads::Mutex::Lock lm (lua_lock);
1683 (*_lua_load)(std::string ((const char*)buf, size));
1684 } catch (luabridge::LuaException const& e) {
1685 cerr << "LuaException:" << e.what () << endl;
1691 if ((child = find_named_node (node, X_("Selection")))) {
1692 _selection->set_state (*child, version);
1695 update_route_record_state ();
1697 /* here beginneth the second phase ... */
1698 set_snapshot_name (_current_snapshot_name);
1700 StateReady (); /* EMIT SIGNAL */
1713 Session::load_routes (const XMLNode& node, int version)
1716 XMLNodeConstIterator niter;
1717 RouteList new_routes;
1719 nlist = node.children();
1723 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1725 boost::shared_ptr<Route> route;
1726 if (version < 3000) {
1727 route = XMLRouteFactory_2X (**niter, version);
1729 route = XMLRouteFactory (**niter, version);
1733 error << _("Session: cannot create Route from XML description.") << endmsg;
1737 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1739 new_routes.push_back (route);
1742 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1744 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1746 BootMessage (_("Finished adding tracks/busses"));
1751 boost::shared_ptr<Route>
1752 Session::XMLRouteFactory (const XMLNode& node, int version)
1754 boost::shared_ptr<Route> ret;
1756 if (node.name() != "Route") {
1760 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1762 DataType type = DataType::AUDIO;
1763 node.get_property("default-type", type);
1765 assert (type != DataType::NIL);
1769 boost::shared_ptr<Track> track;
1771 if (type == DataType::AUDIO) {
1772 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1774 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1777 if (track->init()) {
1781 if (track->set_state (node, version)) {
1785 BOOST_MARK_TRACK (track);
1789 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1790 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1792 if (r->init () == 0 && r->set_state (node, version) == 0) {
1793 BOOST_MARK_ROUTE (r);
1801 boost::shared_ptr<Route>
1802 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1804 boost::shared_ptr<Route> ret;
1806 if (node.name() != "Route") {
1810 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1812 ds_prop = node.property (X_("diskstream"));
1815 DataType type = DataType::AUDIO;
1816 node.get_property("default-type", type);
1818 assert (type != DataType::NIL);
1822 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1823 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1827 if (i == _diskstreams_2X.end()) {
1828 error << _("Could not find diskstream for route") << endmsg;
1829 return boost::shared_ptr<Route> ();
1832 boost::shared_ptr<Track> track;
1834 if (type == DataType::AUDIO) {
1835 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1837 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1840 if (track->init()) {
1844 if (track->set_state (node, version)) {
1848 track->set_diskstream (*i);
1850 BOOST_MARK_TRACK (track);
1854 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1855 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1857 if (r->init () == 0 && r->set_state (node, version) == 0) {
1858 BOOST_MARK_ROUTE (r);
1867 Session::load_regions (const XMLNode& node)
1870 XMLNodeConstIterator niter;
1871 boost::shared_ptr<Region> region;
1873 nlist = node.children();
1877 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1878 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1879 error << _("Session: cannot create Region from XML description.");
1880 XMLProperty const * name = (**niter).property("name");
1883 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1894 Session::load_compounds (const XMLNode& node)
1896 XMLNodeList calist = node.children();
1897 XMLNodeConstIterator caiter;
1898 XMLProperty const * caprop;
1900 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1901 XMLNode* ca = *caiter;
1905 if ((caprop = ca->property (X_("original"))) == 0) {
1908 orig_id = caprop->value();
1910 if ((caprop = ca->property (X_("copy"))) == 0) {
1913 copy_id = caprop->value();
1915 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1916 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1918 if (!orig || !copy) {
1919 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1925 RegionFactory::add_compound_association (orig, copy);
1932 Session::load_nested_sources (const XMLNode& node)
1935 XMLNodeConstIterator niter;
1937 nlist = node.children();
1939 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1940 if ((*niter)->name() == "Source") {
1942 /* it may already exist, so don't recreate it unnecessarily
1945 XMLProperty const * prop = (*niter)->property (X_("id"));
1947 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1951 ID source_id (prop->value());
1953 if (!source_by_id (source_id)) {
1956 SourceFactory::create (*this, **niter, true);
1958 catch (failed_constructor& err) {
1959 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1966 boost::shared_ptr<Region>
1967 Session::XMLRegionFactory (const XMLNode& node, bool full)
1969 XMLProperty const * type = node.property("type");
1973 const XMLNodeList& nlist = node.children();
1975 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1976 XMLNode *child = (*niter);
1977 if (child->name() == "NestedSource") {
1978 load_nested_sources (*child);
1982 if (!type || type->value() == "audio") {
1983 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1984 } else if (type->value() == "midi") {
1985 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1988 } catch (failed_constructor& err) {
1989 return boost::shared_ptr<Region> ();
1992 return boost::shared_ptr<Region> ();
1995 boost::shared_ptr<AudioRegion>
1996 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1998 XMLProperty const * prop;
1999 boost::shared_ptr<Source> source;
2000 boost::shared_ptr<AudioSource> as;
2002 SourceList master_sources;
2003 uint32_t nchans = 1;
2006 if (node.name() != X_("Region")) {
2007 return boost::shared_ptr<AudioRegion>();
2010 node.get_property (X_("channels"), nchans);
2012 if ((prop = node.property ("name")) == 0) {
2013 cerr << "no name for this region\n";
2017 if ((prop = node.property (X_("source-0"))) == 0) {
2018 if ((prop = node.property ("source")) == 0) {
2019 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2020 return boost::shared_ptr<AudioRegion>();
2024 PBD::ID s_id (prop->value());
2026 if ((source = source_by_id (s_id)) == 0) {
2027 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2028 return boost::shared_ptr<AudioRegion>();
2031 as = boost::dynamic_pointer_cast<AudioSource>(source);
2033 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2034 return boost::shared_ptr<AudioRegion>();
2037 sources.push_back (as);
2039 /* pickup other channels */
2041 for (uint32_t n=1; n < nchans; ++n) {
2042 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2043 if ((prop = node.property (buf)) != 0) {
2045 PBD::ID id2 (prop->value());
2047 if ((source = source_by_id (id2)) == 0) {
2048 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2049 return boost::shared_ptr<AudioRegion>();
2052 as = boost::dynamic_pointer_cast<AudioSource>(source);
2054 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2055 return boost::shared_ptr<AudioRegion>();
2057 sources.push_back (as);
2061 for (uint32_t n = 0; n < nchans; ++n) {
2062 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2063 if ((prop = node.property (buf)) != 0) {
2065 PBD::ID id2 (prop->value());
2067 if ((source = source_by_id (id2)) == 0) {
2068 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2069 return boost::shared_ptr<AudioRegion>();
2072 as = boost::dynamic_pointer_cast<AudioSource>(source);
2074 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2075 return boost::shared_ptr<AudioRegion>();
2077 master_sources.push_back (as);
2082 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2084 /* a final detail: this is the one and only place that we know how long missing files are */
2086 if (region->whole_file()) {
2087 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2088 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2090 sfp->set_length (region->length());
2095 if (!master_sources.empty()) {
2096 if (master_sources.size() != nchans) {
2097 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2099 region->set_master_sources (master_sources);
2107 catch (failed_constructor& err) {
2108 return boost::shared_ptr<AudioRegion>();
2112 boost::shared_ptr<MidiRegion>
2113 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2115 XMLProperty const * prop;
2116 boost::shared_ptr<Source> source;
2117 boost::shared_ptr<MidiSource> ms;
2120 if (node.name() != X_("Region")) {
2121 return boost::shared_ptr<MidiRegion>();
2124 if ((prop = node.property ("name")) == 0) {
2125 cerr << "no name for this region\n";
2129 if ((prop = node.property (X_("source-0"))) == 0) {
2130 if ((prop = node.property ("source")) == 0) {
2131 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2132 return boost::shared_ptr<MidiRegion>();
2136 PBD::ID s_id (prop->value());
2138 if ((source = source_by_id (s_id)) == 0) {
2139 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2140 return boost::shared_ptr<MidiRegion>();
2143 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2145 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2146 return boost::shared_ptr<MidiRegion>();
2149 sources.push_back (ms);
2152 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2153 /* a final detail: this is the one and only place that we know how long missing files are */
2155 if (region->whole_file()) {
2156 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2157 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2159 sfp->set_length (region->length());
2167 catch (failed_constructor& err) {
2168 return boost::shared_ptr<MidiRegion>();
2173 Session::get_sources_as_xml ()
2176 XMLNode* node = new XMLNode (X_("Sources"));
2177 Glib::Threads::Mutex::Lock lm (source_lock);
2179 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2180 node->add_child_nocopy (i->second->get_state());
2187 Session::reset_write_sources (bool mark_write_complete, bool force)
2189 boost::shared_ptr<RouteList> rl = routes.reader();
2190 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2191 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2193 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2194 tr->reset_write_sources(mark_write_complete, force);
2195 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2201 Session::load_sources (const XMLNode& node)
2204 XMLNodeConstIterator niter;
2205 /* don't need this but it stops some
2206 * versions of gcc complaining about
2207 * discarded return values.
2209 boost::shared_ptr<Source> source;
2211 nlist = node.children();
2214 std::map<std::string, std::string> relocation;
2216 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2217 #ifdef PLATFORM_WINDOWS
2221 XMLNode srcnode (**niter);
2222 bool try_replace_abspath = true;
2226 #ifdef PLATFORM_WINDOWS
2227 // do not show "insert media" popups (files embedded from removable media).
2228 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2230 if ((source = XMLSourceFactory (srcnode)) == 0) {
2231 error << _("Session: cannot create Source from XML description.") << endmsg;
2233 #ifdef PLATFORM_WINDOWS
2234 SetErrorMode(old_mode);
2237 } catch (MissingSource& err) {
2238 #ifdef PLATFORM_WINDOWS
2239 SetErrorMode(old_mode);
2242 /* try previous abs path replacements first */
2243 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2244 std::string dir = Glib::path_get_dirname (err.path);
2245 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2246 if (rl != relocation.end ()) {
2247 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2248 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2249 srcnode.set_property ("origin", newpath);
2250 try_replace_abspath = false;
2257 _missing_file_replacement = "";
2259 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2260 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2261 PROGRAM_NAME) << endmsg;
2265 if (!no_questions_about_missing_files) {
2266 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2271 switch (user_choice) {
2273 /* user added a new search location
2274 * or selected a new absolute path,
2276 if (Glib::path_is_absolute (err.path)) {
2277 if (!_missing_file_replacement.empty ()) {
2278 /* replace origin, in XML */
2279 std::string newpath = Glib::build_filename (
2280 _missing_file_replacement, Glib::path_get_basename (err.path));
2281 srcnode.set_property ("origin", newpath);
2282 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2283 _missing_file_replacement = "";
2290 /* user asked to quit the entire session load */
2294 no_questions_about_missing_files = true;
2298 no_questions_about_missing_files = true;
2305 case DataType::AUDIO:
2306 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2309 case DataType::MIDI:
2310 /* The MIDI file is actually missing so
2311 * just create a new one in the same
2312 * location. Do not announce its
2316 if (!Glib::path_is_absolute (err.path)) {
2317 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2319 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2324 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2325 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2326 /* reset ID to match the missing one */
2327 source->set_id (**niter);
2328 /* Now we can announce it */
2329 SourceFactory::SourceCreated (source);
2340 boost::shared_ptr<Source>
2341 Session::XMLSourceFactory (const XMLNode& node)
2343 if (node.name() != "Source") {
2344 return boost::shared_ptr<Source>();
2348 /* note: do peak building in another thread when loading session state */
2349 return SourceFactory::create (*this, node, true);
2352 catch (failed_constructor& err) {
2353 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2354 return boost::shared_ptr<Source>();
2359 Session::save_template (string template_name, bool replace_existing)
2361 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2365 bool absolute_path = Glib::path_is_absolute (template_name);
2367 /* directory to put the template in */
2368 std::string template_dir_path;
2370 if (!absolute_path) {
2371 std::string user_template_dir(user_template_directory());
2373 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2374 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2375 user_template_dir, g_strerror (errno)) << endmsg;
2379 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2381 template_dir_path = template_name;
2384 if (!ARDOUR::Profile->get_trx()) {
2385 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2386 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2387 template_dir_path) << endmsg;
2391 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2392 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2393 template_dir_path, g_strerror (errno)) << endmsg;
2399 std::string template_file_path;
2401 if (ARDOUR::Profile->get_trx()) {
2402 template_file_path = template_name;
2404 if (absolute_path) {
2405 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2407 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2411 SessionSaveUnderway (); /* EMIT SIGNAL */
2416 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2417 tree.set_root (&get_template());
2420 if (!tree.write (template_file_path)) {
2421 error << _("template not saved") << endmsg;
2425 store_recent_templates (template_file_path);
2431 Session::refresh_disk_space ()
2433 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2435 Glib::Threads::Mutex::Lock lm (space_lock);
2437 /* get freespace on every FS that is part of the session path */
2439 _total_free_4k_blocks = 0;
2440 _total_free_4k_blocks_uncertain = false;
2442 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2443 #if defined(__NetBSD__)
2444 struct statvfs statfsbuf;
2446 statvfs (i->path.c_str(), &statfsbuf);
2448 struct statfs statfsbuf;
2450 statfs (i->path.c_str(), &statfsbuf);
2452 double const scale = statfsbuf.f_bsize / 4096.0;
2454 /* See if this filesystem is read-only */
2455 struct statvfs statvfsbuf;
2456 statvfs (i->path.c_str(), &statvfsbuf);
2458 /* f_bavail can be 0 if it is undefined for whatever
2459 filesystem we are looking at; Samba shares mounted
2460 via GVFS are an example of this.
2462 if (statfsbuf.f_bavail == 0) {
2463 /* block count unknown */
2465 i->blocks_unknown = true;
2466 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2467 /* read-only filesystem */
2469 i->blocks_unknown = false;
2471 /* read/write filesystem with known space */
2472 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2473 i->blocks_unknown = false;
2476 _total_free_4k_blocks += i->blocks;
2477 if (i->blocks_unknown) {
2478 _total_free_4k_blocks_uncertain = true;
2481 #elif defined PLATFORM_WINDOWS
2482 vector<string> scanned_volumes;
2483 vector<string>::iterator j;
2484 vector<space_and_path>::iterator i;
2485 DWORD nSectorsPerCluster, nBytesPerSector,
2486 nFreeClusters, nTotalClusters;
2490 _total_free_4k_blocks = 0;
2492 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2493 strncpy (disk_drive, (*i).path.c_str(), 3);
2497 volume_found = false;
2498 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2500 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2501 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2502 i->blocks = (uint32_t)(nFreeBytes / 4096);
2504 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2505 if (0 == j->compare(disk_drive)) {
2506 volume_found = true;
2511 if (!volume_found) {
2512 scanned_volumes.push_back(disk_drive);
2513 _total_free_4k_blocks += i->blocks;
2518 if (0 == _total_free_4k_blocks) {
2519 strncpy (disk_drive, path().c_str(), 3);
2522 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2524 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2525 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2526 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2533 Session::get_best_session_directory_for_new_audio ()
2535 vector<space_and_path>::iterator i;
2536 string result = _session_dir->root_path();
2538 /* handle common case without system calls */
2540 if (session_dirs.size() == 1) {
2544 /* OK, here's the algorithm we're following here:
2546 We want to select which directory to use for
2547 the next file source to be created. Ideally,
2548 we'd like to use a round-robin process so as to
2549 get maximum performance benefits from splitting
2550 the files across multiple disks.
2552 However, in situations without much diskspace, an
2553 RR approach may end up filling up a filesystem
2554 with new files while others still have space.
2555 Its therefore important to pay some attention to
2556 the freespace in the filesystem holding each
2557 directory as well. However, if we did that by
2558 itself, we'd keep creating new files in the file
2559 system with the most space until it was as full
2560 as all others, thus negating any performance
2561 benefits of this RAID-1 like approach.
2563 So, we use a user-configurable space threshold. If
2564 there are at least 2 filesystems with more than this
2565 much space available, we use RR selection between them.
2566 If not, then we pick the filesystem with the most space.
2568 This gets a good balance between the two
2572 refresh_disk_space ();
2574 int free_enough = 0;
2576 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2577 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2582 if (free_enough >= 2) {
2583 /* use RR selection process, ensuring that the one
2587 i = last_rr_session_dir;
2590 if (++i == session_dirs.end()) {
2591 i = session_dirs.begin();
2594 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2595 SessionDirectory sdir(i->path);
2596 if (sdir.create ()) {
2598 last_rr_session_dir = i;
2603 } while (i != last_rr_session_dir);
2607 /* pick FS with the most freespace (and that
2608 seems to actually work ...)
2611 vector<space_and_path> sorted;
2612 space_and_path_ascending_cmp cmp;
2614 sorted = session_dirs;
2615 sort (sorted.begin(), sorted.end(), cmp);
2617 for (i = sorted.begin(); i != sorted.end(); ++i) {
2618 SessionDirectory sdir(i->path);
2619 if (sdir.create ()) {
2621 last_rr_session_dir = i;
2631 Session::automation_dir () const
2633 return Glib::build_filename (_path, automation_dir_name);
2637 Session::analysis_dir () const
2639 return Glib::build_filename (_path, analysis_dir_name);
2643 Session::plugins_dir () const
2645 return Glib::build_filename (_path, plugins_dir_name);
2649 Session::externals_dir () const
2651 return Glib::build_filename (_path, externals_dir_name);
2655 Session::load_bundles (XMLNode const & node)
2657 XMLNodeList nlist = node.children();
2658 XMLNodeConstIterator niter;
2662 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2663 if ((*niter)->name() == "InputBundle") {
2664 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2665 } else if ((*niter)->name() == "OutputBundle") {
2666 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2668 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2677 Session::load_route_groups (const XMLNode& node, int version)
2679 XMLNodeList nlist = node.children();
2680 XMLNodeConstIterator niter;
2684 if (version >= 3000) {
2686 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2687 if ((*niter)->name() == "RouteGroup") {
2688 RouteGroup* rg = new RouteGroup (*this, "");
2689 add_route_group (rg);
2690 rg->set_state (**niter, version);
2694 } else if (version < 3000) {
2696 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2697 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2698 RouteGroup* rg = new RouteGroup (*this, "");
2699 add_route_group (rg);
2700 rg->set_state (**niter, version);
2709 state_file_filter (const string &str, void* /*arg*/)
2711 return (str.length() > strlen(statefile_suffix) &&
2712 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2716 remove_end(string state)
2718 string statename(state);
2720 string::size_type start,end;
2721 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2722 statename = statename.substr (start+1);
2725 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2726 end = statename.length();
2729 return string(statename.substr (0, end));
2733 Session::possible_states (string path)
2735 vector<string> states;
2736 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2738 transform(states.begin(), states.end(), states.begin(), remove_end);
2740 sort (states.begin(), states.end());
2746 Session::possible_states () const
2748 return possible_states(_path);
2752 Session::new_route_group (const std::string& name)
2754 RouteGroup* rg = NULL;
2756 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2757 if ((*i)->name () == name) {
2764 rg = new RouteGroup (*this, name);
2765 add_route_group (rg);
2771 Session::add_route_group (RouteGroup* g)
2773 _route_groups.push_back (g);
2774 route_group_added (g); /* EMIT SIGNAL */
2776 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2777 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2778 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2784 Session::remove_route_group (RouteGroup& rg)
2786 list<RouteGroup*>::iterator i;
2788 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2789 _route_groups.erase (i);
2792 route_group_removed (); /* EMIT SIGNAL */
2796 /** Set a new order for our route groups, without adding or removing any.
2797 * @param groups Route group list in the new order.
2800 Session::reorder_route_groups (list<RouteGroup*> groups)
2802 _route_groups = groups;
2804 route_groups_reordered (); /* EMIT SIGNAL */
2810 Session::route_group_by_name (string name)
2812 list<RouteGroup *>::iterator i;
2814 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2815 if ((*i)->name() == name) {
2823 Session::all_route_group() const
2825 return *_all_route_group;
2829 Session::add_commands (vector<Command*> const & cmds)
2831 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2837 Session::add_command (Command* const cmd)
2839 assert (_current_trans);
2840 DEBUG_UNDO_HISTORY (
2841 string_compose ("Current Undo Transaction %1, adding command: %2",
2842 _current_trans->name (),
2844 _current_trans->add_command (cmd);
2847 PBD::StatefulDiffCommand*
2848 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2850 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2856 Session::begin_reversible_command (const string& name)
2858 begin_reversible_command (g_quark_from_string (name.c_str ()));
2861 /** Begin a reversible command using a GQuark to identify it.
2862 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2863 * but there must be as many begin...()s as there are commit...()s.
2866 Session::begin_reversible_command (GQuark q)
2868 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2869 to hold all the commands that are committed. This keeps the order of
2870 commands correct in the history.
2873 if (_current_trans == 0) {
2874 DEBUG_UNDO_HISTORY (string_compose (
2875 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2877 /* start a new transaction */
2878 assert (_current_trans_quarks.empty ());
2879 _current_trans = new UndoTransaction();
2880 _current_trans->set_name (g_quark_to_string (q));
2882 DEBUG_UNDO_HISTORY (
2883 string_compose ("Begin Reversible Command, current transaction: %1",
2884 _current_trans->name ()));
2887 _current_trans_quarks.push_front (q);
2891 Session::abort_reversible_command ()
2893 if (_current_trans != 0) {
2894 DEBUG_UNDO_HISTORY (
2895 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2896 _current_trans->clear();
2897 delete _current_trans;
2899 _current_trans_quarks.clear();
2904 Session::commit_reversible_command (Command *cmd)
2906 assert (_current_trans);
2907 assert (!_current_trans_quarks.empty ());
2912 DEBUG_UNDO_HISTORY (
2913 string_compose ("Current Undo Transaction %1, adding command: %2",
2914 _current_trans->name (),
2916 _current_trans->add_command (cmd);
2919 DEBUG_UNDO_HISTORY (
2920 string_compose ("Commit Reversible Command, current transaction: %1",
2921 _current_trans->name ()));
2923 _current_trans_quarks.pop_front ();
2925 if (!_current_trans_quarks.empty ()) {
2926 DEBUG_UNDO_HISTORY (
2927 string_compose ("Commit Reversible Command, transaction is not "
2928 "top-level, current transaction: %1",
2929 _current_trans->name ()));
2930 /* the transaction we're committing is not the top-level one */
2934 if (_current_trans->empty()) {
2935 /* no commands were added to the transaction, so just get rid of it */
2936 DEBUG_UNDO_HISTORY (
2937 string_compose ("Commit Reversible Command, No commands were "
2938 "added to current transaction: %1",
2939 _current_trans->name ()));
2940 delete _current_trans;
2945 gettimeofday (&now, 0);
2946 _current_trans->set_timestamp (now);
2948 _history.add (_current_trans);
2953 accept_all_audio_files (const string& path, void* /*arg*/)
2955 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2959 if (!AudioFileSource::safe_audio_file_extension (path)) {
2967 accept_all_midi_files (const string& path, void* /*arg*/)
2969 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2973 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2974 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2975 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2979 accept_all_state_files (const string& path, void* /*arg*/)
2981 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2985 std::string const statefile_ext (statefile_suffix);
2986 if (path.length() >= statefile_ext.length()) {
2987 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2994 Session::find_all_sources (string path, set<string>& result)
2999 if (!tree.read (path)) {
3003 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3008 XMLNodeConstIterator niter;
3010 nlist = node->children();
3014 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3016 XMLProperty const * prop;
3018 if ((prop = (*niter)->property (X_("type"))) == 0) {
3022 DataType type (prop->value());
3024 if ((prop = (*niter)->property (X_("name"))) == 0) {
3028 if (Glib::path_is_absolute (prop->value())) {
3029 /* external file, ignore */
3037 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3038 result.insert (found_path);
3046 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3048 vector<string> state_files;
3050 string this_snapshot_path;
3056 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3057 ripped = ripped.substr (0, ripped.length() - 1);
3060 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3062 if (state_files.empty()) {
3067 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3068 this_snapshot_path += statefile_suffix;
3070 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3072 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3074 if (exclude_this_snapshot && *i == this_snapshot_path) {
3075 cerr << "\texcluded\n";
3080 if (find_all_sources (*i, result) < 0) {
3088 struct RegionCounter {
3089 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3090 AudioSourceList::iterator iter;
3091 boost::shared_ptr<Region> region;
3094 RegionCounter() : count (0) {}
3098 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3100 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3101 return r.get_value_or (1);
3105 Session::cleanup_regions ()
3107 bool removed = false;
3108 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3110 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3112 uint32_t used = playlists->region_use_count (i->second);
3114 if (used == 0 && !i->second->automatic ()) {
3115 boost::weak_ptr<Region> w = i->second;
3118 RegionFactory::map_remove (w);
3125 // re-check to remove parent references of compound regions
3126 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3127 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3131 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3132 if (0 == playlists->region_use_count (i->second)) {
3133 boost::weak_ptr<Region> w = i->second;
3135 RegionFactory::map_remove (w);
3142 /* dump the history list */
3149 Session::can_cleanup_peakfiles () const
3151 if (deletion_in_progress()) {
3154 if (!_writable || (_state_of_the_state & CannotSave)) {
3155 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3158 if (record_status() == Recording) {
3159 error << _("Cannot cleanup peak-files while recording") << endmsg;
3166 Session::cleanup_peakfiles ()
3168 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3173 assert (can_cleanup_peakfiles ());
3174 assert (!peaks_cleanup_in_progres());
3176 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3178 int timeout = 5000; // 5 seconds
3179 while (!SourceFactory::files_with_peaks.empty()) {
3180 Glib::usleep (1000);
3181 if (--timeout < 0) {
3182 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3183 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3188 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3189 boost::shared_ptr<AudioSource> as;
3190 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3191 as->close_peakfile();
3195 PBD::clear_directory (session_directory().peak_path());
3197 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3199 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3200 boost::shared_ptr<AudioSource> as;
3201 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3202 SourceFactory::setup_peakfile(as, true);
3209 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3211 pl->deep_sources (*all_sources);
3215 Session::cleanup_sources (CleanupReport& rep)
3217 // FIXME: needs adaptation to midi
3219 vector<boost::shared_ptr<Source> > dead_sources;
3222 vector<string> candidates;
3223 vector<string> unused;
3224 set<string> sources_used_by_all_snapshots;
3231 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3233 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3235 /* this is mostly for windows which doesn't allow file
3236 * renaming if the file is in use. But we don't special
3237 * case it because we need to know if this causes
3238 * problems, and the easiest way to notice that is to
3239 * keep it in place for all platforms.
3242 request_stop (false);
3244 _butler->wait_until_finished ();
3246 /* consider deleting all unused playlists */
3248 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3253 /* sync the "all regions" property of each playlist with its current state */
3255 playlists->sync_all_regions_with_regions ();
3257 /* find all un-used sources */
3262 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3264 SourceMap::iterator tmp;
3269 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3273 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3274 dead_sources.push_back (i->second);
3275 i->second->drop_references ();
3281 /* build a list of all the possible audio directories for the session */
3283 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3284 SessionDirectory sdir ((*i).path);
3285 asp += sdir.sound_path();
3287 audio_path += asp.to_string();
3290 /* build a list of all the possible midi directories for the session */
3292 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3293 SessionDirectory sdir ((*i).path);
3294 msp += sdir.midi_path();
3296 midi_path += msp.to_string();
3298 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3299 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3301 /* add sources from all other snapshots as "used", but don't use this
3302 snapshot because the state file on disk still references sources we
3303 may have already dropped.
3306 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3308 /* Although the region factory has a list of all regions ever created
3309 * for this session, we're only interested in regions actually in
3310 * playlists right now. So merge all playlist regions lists together.
3312 * This will include the playlists used within compound regions.
3315 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3317 /* add our current source list
3320 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3321 boost::shared_ptr<FileSource> fs;
3322 SourceMap::iterator tmp = i;
3325 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3331 /* this is mostly for windows which doesn't allow file
3332 * renaming if the file is in use. But we do not special
3333 * case it because we need to know if this causes
3334 * problems, and the easiest way to notice that is to
3335 * keep it in place for all platforms.
3340 if (!fs->is_stub()) {
3342 /* Note that we're checking a list of all
3343 * sources across all snapshots with the list
3344 * of sources used by this snapshot.
3347 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3348 /* this source is in use by this snapshot */
3349 sources_used_by_all_snapshots.insert (fs->path());
3350 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3352 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3353 /* this source is NOT in use by this snapshot */
3355 /* remove all related regions from RegionFactory master list */
3357 RegionFactory::remove_regions_using_source (i->second);
3359 /* remove from our current source list
3360 * also. We may not remove it from
3361 * disk, because it may be used by
3362 * other snapshots, but it isn't used inside this
3363 * snapshot anymore, so we don't need a
3374 /* now check each candidate source to see if it exists in the list of
3375 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3378 cerr << "Candidates: " << candidates.size() << endl;
3379 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3381 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3386 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3388 tmppath1 = canonical_path (spath);
3389 tmppath2 = canonical_path ((*i));
3391 cerr << "\t => " << tmppath2 << endl;
3393 if (tmppath1 == tmppath2) {
3400 unused.push_back (spath);
3404 cerr << "Actually unused: " << unused.size() << endl;
3406 if (unused.empty()) {
3412 /* now try to move all unused files into the "dead" directory(ies) */
3414 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3419 /* don't move the file across filesystems, just
3420 * stick it in the `dead_dir_name' directory
3421 * on whichever filesystem it was already on.
3424 if ((*x).find ("/sounds/") != string::npos) {
3426 /* old school, go up 1 level */
3428 newpath = Glib::path_get_dirname (*x); // "sounds"
3429 newpath = Glib::path_get_dirname (newpath); // "session-name"
3433 /* new school, go up 4 levels */
3435 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3436 newpath = Glib::path_get_dirname (newpath); // "session-name"
3437 newpath = Glib::path_get_dirname (newpath); // "interchange"
3438 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3441 newpath = Glib::build_filename (newpath, dead_dir_name);
3443 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3444 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3448 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3450 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3452 /* the new path already exists, try versioning */
3454 char buf[PATH_MAX+1];
3458 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3461 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3462 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3466 if (version == 999) {
3467 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3471 newpath = newpath_v;
3476 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3477 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3478 newpath, g_strerror (errno)) << endmsg;
3482 /* see if there an easy to find peakfile for this file, and remove it. */
3484 string base = Glib::path_get_basename (*x);
3485 base += "%A"; /* this is what we add for the channel suffix of all native files,
3486 * or for the first channel of embedded files. it will miss
3487 * some peakfiles for other channels
3489 string peakpath = construct_peak_filepath (base);
3491 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3492 if (::g_unlink (peakpath.c_str ()) != 0) {
3493 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3494 g_strerror (errno)) << endmsg;
3495 /* try to back out */
3496 ::g_rename (newpath.c_str (), _path.c_str ());
3501 rep.paths.push_back (*x);
3502 rep.space += statbuf.st_size;
3505 /* dump the history list */
3509 /* save state so we don't end up a session file
3510 * referring to non-existent sources.
3517 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3523 Session::cleanup_trash_sources (CleanupReport& rep)
3525 // FIXME: needs adaptation for MIDI
3527 vector<space_and_path>::iterator i;
3533 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3535 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3537 clear_directory (dead_dir, &rep.space, &rep.paths);
3544 Session::set_dirty ()
3546 /* return early if there's nothing to do */
3551 /* never mark session dirty during loading */
3552 if (_state_of_the_state & Loading) {
3556 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3557 DirtyChanged(); /* EMIT SIGNAL */
3561 Session::set_clean ()
3563 bool was_dirty = dirty();
3565 _state_of_the_state = Clean;
3568 DirtyChanged(); /* EMIT SIGNAL */
3573 Session::set_deletion_in_progress ()
3575 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3579 Session::clear_deletion_in_progress ()
3581 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3585 Session::add_controllable (boost::shared_ptr<Controllable> c)
3587 /* this adds a controllable to the list managed by the Session.
3588 this is a subset of those managed by the Controllable class
3589 itself, and represents the only ones whose state will be saved
3590 as part of the session.
3593 Glib::Threads::Mutex::Lock lm (controllables_lock);
3594 controllables.insert (c);
3597 struct null_deleter { void operator()(void const *) const {} };
3600 Session::remove_controllable (Controllable* c)
3602 if (_state_of_the_state & Deletion) {
3606 Glib::Threads::Mutex::Lock lm (controllables_lock);
3608 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3610 if (x != controllables.end()) {
3611 controllables.erase (x);
3615 boost::shared_ptr<Controllable>
3616 Session::controllable_by_id (const PBD::ID& id)
3618 Glib::Threads::Mutex::Lock lm (controllables_lock);
3620 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3621 if ((*i)->id() == id) {
3626 return boost::shared_ptr<Controllable>();
3629 boost::shared_ptr<AutomationControl>
3630 Session::automation_control_by_id (const PBD::ID& id)
3632 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3635 boost::shared_ptr<Controllable>
3636 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3638 boost::shared_ptr<Controllable> c;
3639 boost::shared_ptr<Stripable> s;
3640 boost::shared_ptr<Route> r;
3642 switch (desc.top_level_type()) {
3643 case ControllableDescriptor::NamedRoute:
3645 std::string str = desc.top_level_name();
3647 if (str == "Master" || str == "master") {
3649 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3651 } else if (str == "auditioner") {
3654 s = route_by_name (desc.top_level_name());
3660 case ControllableDescriptor::PresentationOrderRoute:
3661 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3664 case ControllableDescriptor::PresentationOrderTrack:
3665 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3668 case ControllableDescriptor::PresentationOrderBus:
3669 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3672 case ControllableDescriptor::PresentationOrderVCA:
3673 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3676 case ControllableDescriptor::SelectionCount:
3677 s = route_by_selected_count (desc.selection_id());
3685 r = boost::dynamic_pointer_cast<Route> (s);
3687 switch (desc.subtype()) {
3688 case ControllableDescriptor::Gain:
3689 c = s->gain_control ();
3692 case ControllableDescriptor::Trim:
3693 c = s->trim_control ();
3696 case ControllableDescriptor::Solo:
3697 c = s->solo_control();
3700 case ControllableDescriptor::Mute:
3701 c = s->mute_control();
3704 case ControllableDescriptor::Recenable:
3705 c = s->rec_enable_control ();
3708 case ControllableDescriptor::PanDirection:
3709 c = s->pan_azimuth_control();
3712 case ControllableDescriptor::PanWidth:
3713 c = s->pan_width_control();
3716 case ControllableDescriptor::PanElevation:
3717 c = s->pan_elevation_control();
3720 case ControllableDescriptor::Balance:
3721 /* XXX simple pan control */
3724 case ControllableDescriptor::PluginParameter:
3726 uint32_t plugin = desc.target (0);
3727 uint32_t parameter_index = desc.target (1);
3729 /* revert to zero based counting */
3735 if (parameter_index > 0) {
3743 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3746 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3747 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3752 case ControllableDescriptor::SendGain: {
3753 uint32_t send = desc.target (0);
3760 c = r->send_level_controllable (send);
3765 /* relax and return a null pointer */
3773 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3776 Stateful::add_instant_xml (node, _path);
3779 if (write_to_config) {
3780 Config->add_instant_xml (node);
3785 Session::instant_xml (const string& node_name)
3787 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3788 if (get_disable_all_loaded_plugins ()) {
3792 return Stateful::instant_xml (node_name, _path);
3796 Session::save_history (string snapshot_name)
3804 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3805 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3809 if (snapshot_name.empty()) {
3810 snapshot_name = _current_snapshot_name;
3813 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3814 const string backup_filename = history_filename + backup_suffix;
3815 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3816 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3818 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3819 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3820 error << _("could not backup old history file, current history not saved") << endmsg;
3825 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3827 if (!tree.write (xml_path))
3829 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3831 if (g_remove (xml_path.c_str()) != 0) {
3832 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3833 xml_path, g_strerror (errno)) << endmsg;
3835 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3836 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3837 backup_path, g_strerror (errno)) << endmsg;
3847 Session::restore_history (string snapshot_name)
3851 if (snapshot_name.empty()) {
3852 snapshot_name = _current_snapshot_name;
3855 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3856 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3858 info << "Loading history from " << xml_path << endmsg;
3860 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3861 info << string_compose (_("%1: no history file \"%2\" for this session."),
3862 _name, xml_path) << endmsg;
3866 if (!tree.read (xml_path)) {
3867 error << string_compose (_("Could not understand session history file \"%1\""),
3868 xml_path) << endmsg;
3875 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3878 UndoTransaction* ut = new UndoTransaction ();
3884 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3885 !t->get_property ("tv-usec", tv_usec)) {
3889 ut->set_name (name);
3893 tv.tv_usec = tv_usec;
3894 ut->set_timestamp(tv);
3896 for (XMLNodeConstIterator child_it = t->children().begin();
3897 child_it != t->children().end(); child_it++)
3899 XMLNode *n = *child_it;
3902 if (n->name() == "MementoCommand" ||
3903 n->name() == "MementoUndoCommand" ||
3904 n->name() == "MementoRedoCommand") {
3906 if ((c = memento_command_factory(n))) {
3910 } else if (n->name() == "NoteDiffCommand") {
3911 PBD::ID id (n->property("midi-source")->value());
3912 boost::shared_ptr<MidiSource> midi_source =
3913 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3915 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3917 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3920 } else if (n->name() == "SysExDiffCommand") {
3922 PBD::ID id (n->property("midi-source")->value());
3923 boost::shared_ptr<MidiSource> midi_source =
3924 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3926 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3928 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3931 } else if (n->name() == "PatchChangeDiffCommand") {
3933 PBD::ID id (n->property("midi-source")->value());
3934 boost::shared_ptr<MidiSource> midi_source =
3935 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3937 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3939 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3942 } else if (n->name() == "StatefulDiffCommand") {
3943 if ((c = stateful_diff_command_factory (n))) {
3944 ut->add_command (c);
3947 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3958 Session::config_changed (std::string p, bool ours)
3964 if (p == "seamless-loop") {
3966 } else if (p == "rf-speed") {
3968 } else if (p == "auto-loop") {
3970 } else if (p == "session-monitoring") {
3972 } else if (p == "auto-input") {
3974 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3975 /* auto-input only makes a difference if we're rolling */
3976 set_track_monitor_input_status (!config.get_auto_input());
3979 } else if (p == "punch-in") {
3983 if ((location = _locations->auto_punch_location()) != 0) {
3985 if (config.get_punch_in ()) {
3986 replace_event (SessionEvent::PunchIn, location->start());
3988 remove_event (location->start(), SessionEvent::PunchIn);
3992 } else if (p == "punch-out") {
3996 if ((location = _locations->auto_punch_location()) != 0) {
3998 if (config.get_punch_out()) {
3999 replace_event (SessionEvent::PunchOut, location->end());
4001 clear_events (SessionEvent::PunchOut);
4005 } else if (p == "edit-mode") {
4007 Glib::Threads::Mutex::Lock lm (playlists->lock);
4009 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4010 (*i)->set_edit_mode (Config->get_edit_mode ());
4013 } else if (p == "use-video-sync") {
4015 waiting_for_sync_offset = config.get_use_video_sync();
4017 } else if (p == "mmc-control") {
4019 //poke_midi_thread ();
4021 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4023 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4025 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4027 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4029 } else if (p == "midi-control") {
4031 //poke_midi_thread ();
4033 } else if (p == "raid-path") {
4035 setup_raid_path (config.get_raid_path());
4037 } else if (p == "timecode-format") {
4041 } else if (p == "video-pullup") {
4045 } else if (p == "seamless-loop") {
4047 if (play_loop && transport_rolling()) {
4048 // to reset diskstreams etc
4049 request_play_loop (true);
4052 } else if (p == "rf-speed") {
4054 cumulative_rf_motion = 0;
4057 } else if (p == "click-sound") {
4059 setup_click_sounds (1);
4061 } else if (p == "click-emphasis-sound") {
4063 setup_click_sounds (-1);
4065 } else if (p == "clicking") {
4067 if (Config->get_clicking()) {
4068 if (_click_io && click_data) { // don't require emphasis data
4075 } else if (p == "click-record-only") {
4077 _click_rec_only = Config->get_click_record_only();
4079 } else if (p == "click-gain") {
4082 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4085 } else if (p == "send-mtc") {
4087 if (Config->get_send_mtc ()) {
4088 /* mark us ready to send */
4089 next_quarter_frame_to_send = 0;
4092 } else if (p == "send-mmc") {
4094 _mmc->enable_send (Config->get_send_mmc ());
4096 } else if (p == "jack-time-master") {
4098 engine().reset_timebase ();
4100 } else if (p == "native-file-header-format") {
4102 if (!first_file_header_format_reset) {
4103 reset_native_file_format ();
4106 first_file_header_format_reset = false;
4108 } else if (p == "native-file-data-format") {
4110 if (!first_file_data_format_reset) {
4111 reset_native_file_format ();
4114 first_file_data_format_reset = false;
4116 } else if (p == "external-sync") {
4117 if (!config.get_external_sync()) {
4118 drop_sync_source ();
4120 switch_to_sync_source (Config->get_sync_source());
4122 } else if (p == "denormal-model") {
4124 } else if (p == "history-depth") {
4125 set_history_depth (Config->get_history_depth());
4126 } else if (p == "remote-model") {
4127 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4130 } else if (p == "initial-program-change") {
4132 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4135 buf[0] = MIDI::program; // channel zero by default
4136 buf[1] = (Config->get_initial_program_change() & 0x7f);
4138 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4140 } else if (p == "solo-mute-override") {
4141 // catch_up_on_solo_mute_override ();
4142 } else if (p == "listen-position" || p == "pfl-position") {
4143 listen_position_changed ();
4144 } else if (p == "solo-control-is-listen-control") {
4145 solo_control_mode_changed ();
4146 } else if (p == "solo-mute-gain") {
4147 _solo_cut_control->Changed (true, Controllable::NoGroup);
4148 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4149 last_timecode_valid = false;
4150 } else if (p == "playback-buffer-seconds") {
4151 AudioSource::allocate_working_buffers (frame_rate());
4152 } else if (p == "ltc-source-port") {
4153 reconnect_ltc_input ();
4154 } else if (p == "ltc-sink-port") {
4155 reconnect_ltc_output ();
4156 } else if (p == "timecode-generator-offset") {
4157 ltc_tx_parse_offset();
4158 } else if (p == "auto-return-target-list") {
4159 follow_playhead_priority ();
4166 Session::set_history_depth (uint32_t d)
4168 _history.set_depth (d);
4172 Session::load_diskstreams_2X (XMLNode const & node, int)
4175 XMLNodeConstIterator citer;
4177 clist = node.children();
4179 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4182 /* diskstreams added automatically by DiskstreamCreated handler */
4183 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4184 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4185 _diskstreams_2X.push_back (dsp);
4187 error << _("Session: unknown diskstream type in XML") << endmsg;
4191 catch (failed_constructor& err) {
4192 error << _("Session: could not load diskstream via XML state") << endmsg;
4200 /** Connect things to the MMC object */
4202 Session::setup_midi_machine_control ()
4204 _mmc = new MIDI::MachineControl;
4206 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4207 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4209 if (!async_out || !async_out) {
4213 /* XXXX argh, passing raw pointers back into libmidi++ */
4215 MIDI::Port* mmc_in = async_in.get();
4216 MIDI::Port* mmc_out = async_out.get();
4218 _mmc->set_ports (mmc_in, mmc_out);
4220 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4221 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4222 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4223 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4224 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4225 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4226 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4227 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4228 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4229 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4230 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4231 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4232 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4234 /* also handle MIDI SPP because its so common */
4236 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4237 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4238 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4241 boost::shared_ptr<Controllable>
4242 Session::solo_cut_control() const
4244 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4245 * controls in Ardour that currently get presented to the user in the GUI that require
4246 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4248 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4249 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4252 return _solo_cut_control;
4256 Session::save_snapshot_name (const std::string & n)
4258 /* assure Stateful::_instant_xml is loaded
4259 * add_instant_xml() only adds to existing data and defaults
4260 * to use an empty Tree otherwise
4262 instant_xml ("LastUsedSnapshot");
4264 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4265 last_used_snapshot->set_property ("name", n);
4266 add_instant_xml (*last_used_snapshot, false);
4270 Session::set_snapshot_name (const std::string & n)
4272 _current_snapshot_name = n;
4273 save_snapshot_name (n);
4277 Session::rename (const std::string& new_name)
4279 string legal_name = legalize_for_path (new_name);
4285 string const old_sources_root = _session_dir->sources_root();
4287 if (!_writable || (_state_of_the_state & CannotSave)) {
4288 error << _("Cannot rename read-only session.") << endmsg;
4289 return 0; // don't show "messed up" warning
4291 if (record_status() == Recording) {
4292 error << _("Cannot rename session while recording") << endmsg;
4293 return 0; // don't show "messed up" warning
4296 StateProtector stp (this);
4301 * interchange subdirectory
4305 * Backup files are left unchanged and not renamed.
4308 /* Windows requires that we close all files before attempting the
4309 * rename. This works on other platforms, but isn't necessary there.
4310 * Leave it in place for all platforms though, since it may help
4311 * catch issues that could arise if the way Source files work ever
4312 * change (since most developers are not using Windows).
4315 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4316 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4322 /* pass one: not 100% safe check that the new directory names don't
4326 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4330 /* this is a stupid hack because Glib::path_get_dirname() is
4331 * lexical-only, and so passing it /a/b/c/ gives a different
4332 * result than passing it /a/b/c ...
4335 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4336 oldstr = oldstr.substr (0, oldstr.length() - 1);
4339 string base = Glib::path_get_dirname (oldstr);
4341 newstr = Glib::build_filename (base, legal_name);
4343 cerr << "Looking for " << newstr << endl;
4345 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4346 cerr << " exists\n";
4355 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4361 /* this is a stupid hack because Glib::path_get_dirname() is
4362 * lexical-only, and so passing it /a/b/c/ gives a different
4363 * result than passing it /a/b/c ...
4366 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4367 oldstr = oldstr.substr (0, oldstr.length() - 1);
4370 string base = Glib::path_get_dirname (oldstr);
4371 newstr = Glib::build_filename (base, legal_name);
4373 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4375 cerr << "Rename " << oldstr << " => " << newstr << endl;
4376 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4377 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4378 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4382 /* Reset path in "session dirs" */
4387 /* reset primary SessionDirectory object */
4390 (*_session_dir) = newstr;
4395 /* now rename directory below session_dir/interchange */
4397 string old_interchange_dir;
4398 string new_interchange_dir;
4400 /* use newstr here because we renamed the path
4401 * (folder/directory) that used to be oldstr to newstr above
4404 v.push_back (newstr);
4405 v.push_back (interchange_dir_name);
4406 v.push_back (Glib::path_get_basename (oldstr));
4408 old_interchange_dir = Glib::build_filename (v);
4411 v.push_back (newstr);
4412 v.push_back (interchange_dir_name);
4413 v.push_back (legal_name);
4415 new_interchange_dir = Glib::build_filename (v);
4417 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4419 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4420 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4421 old_interchange_dir, new_interchange_dir,
4424 error << string_compose (_("renaming %s as %2 failed (%3)"),
4425 old_interchange_dir, new_interchange_dir,
4434 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4435 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4437 cerr << "Rename " << oldstr << " => " << newstr << endl;
4439 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4440 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4441 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4447 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4449 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4450 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4452 cerr << "Rename " << oldstr << " => " << newstr << endl;
4454 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4455 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4456 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4461 /* remove old name from recent sessions */
4462 remove_recent_sessions (_path);
4465 /* update file source paths */
4467 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4468 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4470 string p = fs->path ();
4471 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4473 SourceFactory::setup_peakfile(i->second, true);
4477 set_snapshot_name (new_name);
4482 /* save state again to get everything just right */
4484 save_state (_current_snapshot_name);
4486 /* add to recent sessions */
4488 store_recent_sessions (new_name, _path);
4494 Session::parse_stateful_loading_version (const std::string& version)
4496 if (version.empty ()) {
4497 /* no version implies very old version of Ardour */
4501 if (version.find ('.') != string::npos) {
4502 /* old school version format */
4503 if (version[0] == '2') {
4509 return string_to<int32_t>(version);
4514 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4516 bool found_sr = false;
4517 bool found_data_format = false;
4518 std::string version;
4519 program_version = "";
4521 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4525 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4529 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4532 xmlFreeParserCtxt(ctxt);
4536 xmlNodePtr node = xmlDocGetRootElement(doc);
4539 xmlFreeParserCtxt(ctxt);
4544 /* sample rate & version*/
4547 for (attr = node->properties; attr; attr = attr->next) {
4548 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4549 version = std::string ((char*)attr->children->content);
4551 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4552 sample_rate = atoi ((char*)attr->children->content);
4557 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4561 node = node->children;
4562 while (node != NULL) {
4563 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4564 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4566 program_version = string ((const char*)val);
4567 size_t sep = program_version.find_first_of("-");
4568 if (sep != string::npos) {
4569 program_version = program_version.substr (0, sep);
4574 if (strcmp((const char*) node->name, "Config")) {
4578 for (node = node->children; node; node = node->next) {
4579 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4580 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4582 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4585 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4587 found_data_format = true;
4588 } catch (PBD::unknown_enumeration& e) {}
4598 xmlFreeParserCtxt(ctxt);
4601 return (found_sr && found_data_format) ? 0 : 1;
4605 Session::get_snapshot_from_instant (const std::string& session_dir)
4607 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4609 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4614 if (!tree.read (instant_xml_path)) {
4618 XMLProperty const * prop;
4619 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4620 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4621 return prop->value();
4627 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4628 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4631 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4635 SourcePathMap source_path_map;
4637 boost::shared_ptr<AudioFileSource> afs;
4642 Glib::Threads::Mutex::Lock lm (source_lock);
4644 cerr << " total sources = " << sources.size();
4646 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4647 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4653 if (fs->within_session()) {
4657 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4658 source_path_map[fs->path()].push_back (fs);
4660 SeveralFileSources v;
4662 source_path_map.insert (make_pair (fs->path(), v));
4668 cerr << " fsources = " << total << endl;
4670 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4672 /* tell caller where we are */
4674 string old_path = i->first;
4676 callback (n, total, old_path);
4678 cerr << old_path << endl;
4682 switch (i->second.front()->type()) {
4683 case DataType::AUDIO:
4684 new_path = new_audio_source_path_for_embedded (old_path);
4687 case DataType::MIDI:
4688 /* XXX not implemented yet */
4692 if (new_path.empty()) {
4696 cerr << "Move " << old_path << " => " << new_path << endl;
4698 if (!copy_file (old_path, new_path)) {
4699 cerr << "failed !\n";
4703 /* make sure we stop looking in the external
4704 dir/folder. Remember, this is an all-or-nothing
4705 operations, it doesn't merge just some files.
4707 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4709 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4710 (*f)->set_path (new_path);
4715 save_state ("", false, false);
4721 bool accept_all_files (string const &, void *)
4727 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4729 /* 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.
4734 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4736 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4738 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4740 v.push_back (new_session_folder); /* full path */
4741 v.push_back (interchange_dir_name);
4742 v.push_back (new_session_path); /* just one directory/folder */
4743 v.push_back (typedir);
4744 v.push_back (Glib::path_get_basename (old_path));
4746 return Glib::build_filename (v);
4750 Session::save_as (SaveAs& saveas)
4752 vector<string> files;
4753 string current_folder = Glib::path_get_dirname (_path);
4754 string new_folder = legalize_for_path (saveas.new_name);
4755 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4756 int64_t total_bytes = 0;
4760 int32_t internal_file_cnt = 0;
4762 vector<string> do_not_copy_extensions;
4763 do_not_copy_extensions.push_back (statefile_suffix);
4764 do_not_copy_extensions.push_back (pending_suffix);
4765 do_not_copy_extensions.push_back (backup_suffix);
4766 do_not_copy_extensions.push_back (temp_suffix);
4767 do_not_copy_extensions.push_back (history_suffix);
4769 /* get total size */
4771 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4773 /* need to clear this because
4774 * find_files_matching_filter() is cumulative
4779 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4781 all += files.size();
4783 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4785 g_stat ((*i).c_str(), &gsb);
4786 total_bytes += gsb.st_size;
4790 /* save old values so we can switch back if we are not switching to the new session */
4792 string old_path = _path;
4793 string old_name = _name;
4794 string old_snapshot = _current_snapshot_name;
4795 string old_sd = _session_dir->root_path();
4796 vector<string> old_search_path[DataType::num_types];
4797 string old_config_search_path[DataType::num_types];
4799 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4800 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4801 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4802 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4804 /* switch session directory */
4806 (*_session_dir) = to_dir;
4808 /* create new tree */
4810 if (!_session_dir->create()) {
4811 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4816 /* copy all relevant files. Find each location in session_dirs,
4817 * and copy files from there to target.
4820 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4822 /* need to clear this because
4823 * find_files_matching_filter() is cumulative
4828 const size_t prefix_len = (*sd).path.size();
4830 /* Work just on the files within this session dir */
4832 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4834 /* add dir separator to protect against collisions with
4835 * track names (e.g. track named "audiofiles" or
4839 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4840 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4841 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4843 /* copy all the files. Handling is different for media files
4844 than others because of the *silly* subtree we have below the interchange
4845 folder. That really was a bad idea, but I'm not fixing it as part of
4846 implementing ::save_as().
4849 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4851 std::string from = *i;
4854 string filename = Glib::path_get_basename (from);
4855 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4856 if (filename == ".DS_STORE") {
4861 if (from.find (audiofile_dir_string) != string::npos) {
4863 /* audio file: only copy if asked */
4865 if (saveas.include_media && saveas.copy_media) {
4867 string to = make_new_media_path (*i, to_dir, new_folder);
4869 info << "media file copying from " << from << " to " << to << endmsg;
4871 if (!copy_file (from, to)) {
4872 throw Glib::FileError (Glib::FileError::IO_ERROR,
4873 string_compose(_("\ncopying \"%1\" failed !"), from));
4877 /* we found media files inside the session folder */
4879 internal_file_cnt++;
4881 } else if (from.find (midifile_dir_string) != string::npos) {
4883 /* midi file: always copy unless
4884 * creating an empty new session
4887 if (saveas.include_media) {
4889 string to = make_new_media_path (*i, to_dir, new_folder);
4891 info << "media file copying from " << from << " to " << to << endmsg;
4893 if (!copy_file (from, to)) {
4894 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4898 /* we found media files inside the session folder */
4900 internal_file_cnt++;
4902 } else if (from.find (analysis_dir_string) != string::npos) {
4904 /* make sure analysis dir exists in
4905 * new session folder, but we're not
4906 * copying analysis files here, see
4910 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4915 /* normal non-media file. Don't copy state, history, etc.
4918 bool do_copy = true;
4920 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4921 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4922 /* end of filename matches extension, do not copy file */
4928 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4929 /* don't copy peakfiles if
4930 * we're not copying media
4936 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4938 info << "attempting to make directory/folder " << to << endmsg;
4940 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4941 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4944 info << "attempting to copy " << from << " to " << to << endmsg;
4946 if (!copy_file (from, to)) {
4947 throw Glib::FileError (Glib::FileError::IO_ERROR,
4948 string_compose(_("\ncopying \"%1\" failed !"), from));
4953 /* measure file size even if we're not going to copy so that our Progress
4954 signals are correct, since we included these do-not-copy files
4955 in the computation of the total size and file count.
4959 g_stat (from.c_str(), &gsb);
4960 copied += gsb.st_size;
4963 double fraction = (double) copied / total_bytes;
4965 bool keep_going = true;
4967 if (saveas.copy_media) {
4969 /* no need or expectation of this if
4970 * media is not being copied, because
4971 * it will be fast(ish).
4974 /* tell someone "X percent, file M of N"; M is one-based */
4976 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4984 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4990 /* copy optional folders, if any */
4992 string old = plugins_dir ();
4993 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4994 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4995 copy_files (old, newdir);
4998 old = externals_dir ();
4999 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5000 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5001 copy_files (old, newdir);
5004 old = automation_dir ();
5005 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5006 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5007 copy_files (old, newdir);
5010 if (saveas.include_media) {
5012 if (saveas.copy_media) {
5013 #ifndef PLATFORM_WINDOWS
5014 /* There are problems with analysis files on
5015 * Windows, because they used a colon in their
5016 * names as late as 4.0. Colons are not legal
5017 * under Windows even if NTFS allows them.
5019 * This is a tricky problem to solve so for
5020 * just don't copy these files. They will be
5021 * regenerated as-needed anyway, subject to the
5022 * existing issue that the filenames will be
5023 * rejected by Windows, which is a separate
5024 * problem (though related).
5027 /* only needed if we are copying media, since the
5028 * analysis data refers to media data
5031 old = analysis_dir ();
5032 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5033 string newdir = Glib::build_filename (to_dir, "analysis");
5034 copy_files (old, newdir);
5036 #endif /* PLATFORM_WINDOWS */
5041 set_snapshot_name (saveas.new_name);
5042 _name = saveas.new_name;
5044 if (saveas.include_media && !saveas.copy_media) {
5046 /* reset search paths of the new session (which we're pretending to be right now) to
5047 include the original session search path, so we can still find all audio.
5050 if (internal_file_cnt) {
5051 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5052 ensure_search_path_includes (*s, DataType::AUDIO);
5053 cerr << "be sure to include " << *s << " for audio" << endl;
5056 /* we do not do this for MIDI because we copy
5057 all MIDI files if saveas.include_media is
5063 bool was_dirty = dirty ();
5065 save_default_options ();
5067 if (saveas.copy_media && saveas.copy_external) {
5068 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5069 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5073 saveas.final_session_folder_name = _path;
5075 store_recent_sessions (_name, _path);
5077 if (!saveas.switch_to) {
5079 /* save the new state */
5081 save_state ("", false, false, !saveas.include_media);
5083 /* switch back to the way things were */
5087 set_snapshot_name (old_snapshot);
5089 (*_session_dir) = old_sd;
5095 if (internal_file_cnt) {
5096 /* reset these to their original values */
5097 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5098 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5103 /* prune session dirs, and update disk space statistics
5108 session_dirs.clear ();
5109 session_dirs.push_back (sp);
5110 refresh_disk_space ();
5112 _writable = exists_and_writable (_path);
5114 /* ensure that all existing tracks reset their current capture source paths
5116 reset_write_sources (true, true);
5118 /* creating new write sources marks the session as
5119 dirty. If the new session is empty, then
5120 save_state() thinks we're saving a template and will
5121 not mark the session as clean. So do that here,
5122 before we save state.
5125 if (!saveas.include_media) {
5126 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5129 save_state ("", false, false, !saveas.include_media);
5131 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5132 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5135 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5136 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5142 if (fs->within_session()) {
5143 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5144 fs->set_path (newpath);
5149 } catch (Glib::FileError& e) {
5151 saveas.failure_message = e.what();
5153 /* recursively remove all the directories */
5155 remove_directory (to_dir);
5163 saveas.failure_message = _("unknown reason");
5165 /* recursively remove all the directories */
5167 remove_directory (to_dir);
5177 static void set_progress (Progress* p, size_t n, size_t t)
5179 p->set_progress (float (n) / float(t));
5183 Session::archive_session (const std::string& dest,
5184 const std::string& name,
5185 ArchiveEncode compress_audio,
5186 bool only_used_sources,
5189 if (dest.empty () || name.empty ()) {
5193 /* save current values */
5194 bool was_dirty = dirty ();
5195 string old_path = _path;
5196 string old_name = _name;
5197 string old_snapshot = _current_snapshot_name;
5198 string old_sd = _session_dir->root_path();
5199 string old_config_search_path[DataType::num_types];
5200 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5201 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5203 /* ensure that session-path is included in search-path */
5205 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5206 if ((*sd).path == old_path) {
5214 /* create temporary dir to save session to */
5215 #ifdef PLATFORM_WINDOWS
5216 char tmp[256] = "C:\\TEMP\\";
5217 GetTempPath (sizeof (tmp), tmp);
5219 char const* tmp = getenv("TMPDIR");
5224 if ((strlen (tmp) + 21) > 1024) {
5229 strcpy (tmptpl, tmp);
5230 strcat (tmptpl, "ardourarchive-XXXXXX");
5231 char* tmpdir = g_mkdtemp (tmptpl);
5237 std::string to_dir = std::string (tmpdir);
5239 /* switch session directory temporarily */
5240 (*_session_dir) = to_dir;
5242 if (!_session_dir->create()) {
5243 (*_session_dir) = old_sd;
5244 remove_directory (to_dir);
5248 /* prepare archive */
5249 string archive = Glib::build_filename (dest, name + ".tar.xz");
5251 PBD::ScopedConnectionList progress_connection;
5252 PBD::FileArchive ar (archive);
5254 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5257 /* collect files to archive */
5258 std::map<string,string> filemap;
5260 vector<string> do_not_copy_extensions;
5261 do_not_copy_extensions.push_back (statefile_suffix);
5262 do_not_copy_extensions.push_back (pending_suffix);
5263 do_not_copy_extensions.push_back (backup_suffix);
5264 do_not_copy_extensions.push_back (temp_suffix);
5265 do_not_copy_extensions.push_back (history_suffix);
5267 vector<string> blacklist_dirs;
5268 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5269 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5270 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5271 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5272 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5273 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5275 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5276 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5278 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5279 if (only_used_sources) {
5280 playlists->sync_all_regions_with_regions ();
5281 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5284 // collect audio sources for this session, calc total size for encoding
5285 // add option to only include *used* sources (see Session::cleanup_sources)
5286 size_t total_size = 0;
5288 Glib::Threads::Mutex::Lock lm (source_lock);
5289 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5290 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5291 if (!afs || afs->readable_length () == 0) {
5295 if (only_used_sources) {
5299 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5304 std::string from = afs->path();
5306 if (compress_audio != NO_ENCODE) {
5307 total_size += afs->readable_length ();
5309 if (afs->within_session()) {
5310 filemap[from] = make_new_media_path (from, name, name);
5312 filemap[from] = make_new_media_path (from, name, name);
5313 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5320 if (compress_audio != NO_ENCODE) {
5322 progress->set_progress (2); // set to "encoding"
5323 progress->set_progress (0);
5326 Glib::Threads::Mutex::Lock lm (source_lock);
5327 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5328 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5329 if (!afs || afs->readable_length () == 0) {
5333 if (only_used_sources) {
5337 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5342 orig_sources[afs] = afs->path();
5343 orig_gain[afs] = afs->gain();
5345 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5346 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5347 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5350 progress->descend ((float)afs->readable_length () / total_size);
5354 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5355 afs->replace_file (new_path);
5356 afs->set_gain (ns->gain(), true);
5359 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5363 progress->ascend ();
5369 progress->set_progress (-1); // set to "archiving"
5370 progress->set_progress (0);
5373 /* index files relevant for this session */
5374 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5375 vector<string> files;
5377 size_t prefix_len = (*sd).path.size();
5378 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5382 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5384 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5385 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5386 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5388 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5389 std::string from = *i;
5392 string filename = Glib::path_get_basename (from);
5393 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5394 if (filename == ".DS_STORE") {
5399 if (from.find (audiofile_dir_string) != string::npos) {
5401 } else if (from.find (midifile_dir_string) != string::npos) {
5402 filemap[from] = make_new_media_path (from, name, name);
5403 } else if (from.find (videofile_dir_string) != string::npos) {
5404 filemap[from] = make_new_media_path (from, name, name);
5406 bool do_copy = true;
5407 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5408 if (from.find (*v) != string::npos) {
5413 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5414 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5421 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5427 /* write session file */
5429 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5431 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5434 save_default_options ();
5436 size_t prefix_len = _path.size();
5437 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5441 /* collect session-state files */
5442 vector<string> files;
5443 do_not_copy_extensions.clear ();
5444 do_not_copy_extensions.push_back (history_suffix);
5446 blacklist_dirs.clear ();
5447 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5449 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5450 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5451 std::string from = *i;
5452 bool do_copy = true;
5453 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5454 if (from.find (*v) != string::npos) {
5459 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5460 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5466 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5470 /* restore original values */
5473 set_snapshot_name (old_snapshot);
5474 (*_session_dir) = old_sd;
5478 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5479 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5481 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5482 i->first->replace_file (i->second);
5484 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5485 i->first->set_gain (i->second, true);
5488 int rv = ar.create (filemap);
5489 remove_directory (to_dir);
5495 Session::undo (uint32_t n)
5497 if (actively_recording()) {
5505 Session::redo (uint32_t n)
5507 if (actively_recording()) {