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));
269 /* MidiClock requires a tempo map */
272 midi_clock = new MidiClockTicker ();
273 midi_clock->set_session (this);
275 /* crossfades require sample rate knowledge */
277 SndFileSource::setup_standard_crossfades (*this, frame_rate());
278 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
279 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
281 AudioDiskstream::allocate_working_buffers();
282 refresh_disk_space ();
284 /* we're finally ready to call set_state() ... all objects have
285 * been created, the engine is running.
289 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
290 error << _("Could not set session state from XML") << endmsg;
294 // set_state() will call setup_raid_path(), but if it's a new session we need
295 // to call setup_raid_path() here.
296 setup_raid_path (_path);
301 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
302 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
304 Config->map_parameters (ff);
305 config.map_parameters (ft);
306 _butler->map_parameters ();
308 /* Reset all panners */
310 Delivery::reset_panners ();
312 /* this will cause the CPM to instantiate any protocols that are in use
313 * (or mandatory), which will pass it this Session, and then call
314 * set_state() on each instantiated protocol to match stored state.
317 ControlProtocolManager::instance().set_session (this);
319 /* This must be done after the ControlProtocolManager set_session above,
320 as it will set states for ports which the ControlProtocolManager creates.
323 // XXX set state of MIDI::Port's
324 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
326 /* And this must be done after the MIDI::Manager::set_port_states as
327 * it will try to make connections whose details are loaded by set_port_states.
332 /* Let control protocols know that we are now all connected, so they
333 * could start talking to surfaces if they want to.
336 ControlProtocolManager::instance().midi_connectivity_established ();
338 if (_is_new && !no_auto_connect()) {
339 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
340 auto_connect_master_bus ();
343 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
345 /* update latencies */
347 initialize_latencies ();
349 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
350 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
351 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
353 } catch (AudioEngine::PortRegistrationFailure& err) {
354 /* handle this one in a different way than all others, so that its clear what happened */
355 error << err.what() << endmsg;
357 } catch (std::exception const & e) {
358 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
361 error << _("Unknown exception during session setup") << endmsg;
365 BootMessage (_("Reset Remote Controls"));
367 // send_full_time_code (0);
368 _engine.transport_locate (0);
370 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
371 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
373 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
376 /* initial program change will be delivered later; see ::config_changed() */
378 _state_of_the_state = Clean;
380 Port::set_connecting_blocked (false);
382 DirtyChanged (); /* EMIT SIGNAL */
386 } else if (state_was_pending) {
388 remove_pending_capture_state ();
389 state_was_pending = false;
392 /* Now, finally, we can fill the playback buffers */
394 BootMessage (_("Filling playback buffers"));
396 boost::shared_ptr<RouteList> rl = routes.reader();
397 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
398 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
399 if (trk && !trk->hidden()) {
400 trk->seek (_transport_frame, true);
408 Session::session_loaded ()
412 _state_of_the_state = Clean;
414 DirtyChanged (); /* EMIT SIGNAL */
418 } else if (state_was_pending) {
420 remove_pending_capture_state ();
421 state_was_pending = false;
424 /* Now, finally, we can fill the playback buffers */
426 BootMessage (_("Filling playback buffers"));
427 force_locate (_transport_frame, false);
431 Session::raid_path () const
433 Searchpath raid_search_path;
435 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
436 raid_search_path += (*i).path;
439 return raid_search_path.to_string ();
443 Session::setup_raid_path (string path)
452 session_dirs.clear ();
454 Searchpath search_path(path);
455 Searchpath sound_search_path;
456 Searchpath midi_search_path;
458 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
460 sp.blocks = 0; // not needed
461 session_dirs.push_back (sp);
463 SessionDirectory sdir(sp.path);
465 sound_search_path += sdir.sound_path ();
466 midi_search_path += sdir.midi_path ();
469 // reset the round-robin soundfile path thingie
470 last_rr_session_dir = session_dirs.begin();
474 Session::path_is_within_session (const std::string& path)
476 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
477 if (PBD::path_is_within (i->path, path)) {
485 Session::ensure_subdirs ()
489 dir = session_directory().peak_path();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = session_directory().sound_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().midi_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = session_directory().dead_path();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = session_directory().export_path();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = analysis_dir ();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 dir = plugins_dir ();
533 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
534 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
538 dir = externals_dir ();
540 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
541 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
548 /** @param session_template directory containing session template, or empty.
549 * Caller must not hold process lock.
552 Session::create (const string& session_template, BusProfile* bus_profile)
554 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
555 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
559 if (ensure_subdirs ()) {
563 _writable = exists_and_writable (_path);
565 if (!session_template.empty()) {
566 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
568 FILE* in = g_fopen (in_path.c_str(), "rb");
571 /* no need to call legalize_for_path() since the string
572 * in session_template is already a legal path name
574 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
576 FILE* out = g_fopen (out_path.c_str(), "wb");
580 stringstream new_session;
583 size_t charsRead = fread (buf, sizeof(char), 1024, in);
586 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
591 if (charsRead == 0) {
594 new_session.write (buf, charsRead);
598 string file_contents = new_session.str();
599 size_t writeSize = file_contents.length();
600 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
601 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
609 if (!ARDOUR::Profile->get_trx()) {
610 /* Copy plugin state files from template to new session */
611 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
612 copy_recurse (template_plugins, plugins_dir ());
618 error << string_compose (_("Could not open %1 for writing session template"), out_path)
625 error << string_compose (_("Could not open session template %1 for reading"), in_path)
632 if (Profile->get_trx()) {
634 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
635 * Remember that this is a brand new session. Sessions
636 * loaded from saved state will get this range from the saved state.
639 set_session_range_location (0, 0);
641 /* Initial loop location, from absolute zero, length 10 seconds */
643 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
644 _locations->add (loc, true);
645 set_auto_loop_location (loc);
648 _state_of_the_state = Clean;
650 /* set up Master Out and Monitor Out if necessary */
655 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
657 // Waves Tracks: always create master bus for Tracks
658 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
659 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
667 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
668 r->input()->ensure_io (count, false, this);
669 r->output()->ensure_io (count, false, this);
675 /* prohibit auto-connect to master, because there isn't one */
676 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
680 add_routes (rl, false, false, false, PresentationInfo::max_order);
683 // Waves Tracks: Skip this. Always use autoconnection for Tracks
684 if (!ARDOUR::Profile->get_trx()) {
686 /* this allows the user to override settings with an environment variable.
689 if (no_auto_connect()) {
690 bus_profile->input_ac = AutoConnectOption (0);
691 bus_profile->output_ac = AutoConnectOption (0);
694 Config->set_input_auto_connect (bus_profile->input_ac);
695 Config->set_output_auto_connect (bus_profile->output_ac);
699 if (Config->get_use_monitor_bus() && bus_profile) {
700 add_monitor_section ();
707 Session::maybe_write_autosave()
709 if (dirty() && record_status() != Recording) {
710 save_state("", true);
715 Session::remove_pending_capture_state ()
717 std::string pending_state_file_path(_session_dir->root_path());
719 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
721 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
723 if (g_remove (pending_state_file_path.c_str()) != 0) {
724 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
725 pending_state_file_path, g_strerror (errno)) << endmsg;
729 /** Rename a state file.
730 * @param old_name Old snapshot name.
731 * @param new_name New snapshot name.
734 Session::rename_state (string old_name, string new_name)
736 if (old_name == _current_snapshot_name || old_name == _name) {
737 /* refuse to rename the current snapshot or the "main" one */
741 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
742 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
744 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
745 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
747 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
748 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
749 old_name, new_name, g_strerror(errno)) << endmsg;
753 /** Remove a state file.
754 * @param snapshot_name Snapshot name.
757 Session::remove_state (string snapshot_name)
759 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
760 // refuse to remove the current snapshot or the "main" one
764 std::string xml_path(_session_dir->root_path());
766 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
768 if (!create_backup_file (xml_path)) {
769 // don't remove it if a backup can't be made
770 // create_backup_file will log the error.
775 if (g_remove (xml_path.c_str()) != 0) {
776 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
777 xml_path, g_strerror (errno)) << endmsg;
781 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
783 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
785 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
788 std::string xml_path(_session_dir->root_path());
790 /* prevent concurrent saves from different threads */
792 Glib::Threads::Mutex::Lock lm (save_state_lock);
794 if (!_writable || (_state_of_the_state & CannotSave)) {
798 if (g_atomic_int_get(&_suspend_save)) {
802 _save_queued = false;
804 if (!_engine.connected ()) {
805 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), PROGRAM_NAME)
810 snapshot_t fork_state = NormalSave;
811 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
812 /* snapshot, close midi */
813 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
817 const int64_t save_start_time = g_get_monotonic_time();
820 /* tell sources we're saving first, in case they write out to a new file
821 * which should be saved with the state rather than the old one */
822 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
824 i->second->session_saved();
825 } catch (Evoral::SMF::FileError& e) {
826 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
830 SessionSaveUnderway (); /* EMIT SIGNAL */
832 bool mark_as_clean = true;
834 if (!snapshot_name.empty() && !switch_to_snapshot) {
835 mark_as_clean = false;
839 mark_as_clean = false;
840 tree.set_root (&get_template());
842 tree.set_root (&state (true, fork_state));
845 if (snapshot_name.empty()) {
846 snapshot_name = _current_snapshot_name;
847 } else if (switch_to_snapshot) {
848 set_snapshot_name (snapshot_name);
851 assert (!snapshot_name.empty());
855 /* proper save: use statefile_suffix (.ardour in English) */
857 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
859 /* make a backup copy of the old file */
861 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
862 // create_backup_file will log the error
868 /* pending save: use pending_suffix (.pending in English) */
869 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
872 std::string tmp_path(_session_dir->root_path());
873 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
875 cerr << "actually writing state to " << tmp_path << endl;
877 if (!tree.write (tmp_path)) {
878 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
879 if (g_remove (tmp_path.c_str()) != 0) {
880 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
881 tmp_path, g_strerror (errno)) << endmsg;
887 cerr << "renaming state to " << xml_path << endl;
889 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
890 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
891 tmp_path, xml_path, g_strerror(errno)) << endmsg;
892 if (g_remove (tmp_path.c_str()) != 0) {
893 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
894 tmp_path, g_strerror (errno)) << endmsg;
902 save_history (snapshot_name);
905 bool was_dirty = dirty();
907 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
910 DirtyChanged (); /* EMIT SIGNAL */
914 StateSaved (snapshot_name); /* EMIT SIGNAL */
918 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
919 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
925 Session::restore_state (string snapshot_name)
927 if (load_state (snapshot_name) == 0) {
928 set_state (*state_tree->root(), Stateful::loading_state_version);
935 Session::load_state (string snapshot_name)
940 state_was_pending = false;
942 /* check for leftover pending state from a crashed capture attempt */
944 std::string xmlpath(_session_dir->root_path());
945 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
947 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
949 /* there is pending state from a crashed capture attempt */
951 boost::optional<int> r = AskAboutPendingState();
952 if (r.get_value_or (1)) {
953 state_was_pending = true;
957 if (!state_was_pending) {
958 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
961 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
962 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
963 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
964 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
969 state_tree = new XMLTree;
973 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
975 if (!state_tree->read (xmlpath)) {
976 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
982 XMLNode const & root (*state_tree->root());
984 if (root.name() != X_("Session")) {
985 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
992 if (root.get_property ("version", version)) {
993 if (version.find ('.') != string::npos) {
994 /* old school version format */
995 if (version[0] == '2') {
996 Stateful::loading_state_version = 2000;
998 Stateful::loading_state_version = 3000;
1001 Stateful::loading_state_version = string_to<int32_t>(version);
1004 /* no version implies very old version of Ardour */
1005 Stateful::loading_state_version = 1000;
1008 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1010 std::string backup_path(_session_dir->root_path());
1011 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1012 backup_path = Glib::build_filename (backup_path, backup_filename);
1014 // only create a backup for a given statefile version once
1016 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1018 VersionMismatch (xmlpath, backup_path);
1020 if (!copy_file (xmlpath, backup_path)) {;
1026 save_snapshot_name (snapshot_name);
1032 Session::load_options (const XMLNode& node)
1034 config.set_variables (node);
1039 Session::save_default_options ()
1041 return config.save_state();
1045 Session::get_state()
1051 Session::get_template()
1053 /* if we don't disable rec-enable, diskstreams
1054 will believe they need to store their capture
1055 sources in their state node.
1058 disable_record (false);
1060 return state(false);
1063 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1064 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1067 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1069 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1072 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1076 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1079 XMLNode* node = new XMLNode("TrackState"); // XXX
1082 PlaylistSet playlists; // SessionPlaylists
1085 // these will work with new_route_from_template()
1086 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1087 child = node->add_child ("Routes");
1088 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1089 if ((*i)->is_auditioner()) {
1092 if ((*i)->is_master() || (*i)->is_monitor()) {
1095 child->add_child_nocopy ((*i)->get_state());
1096 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1098 playlists.insert (track->playlist ());
1102 // on load, Regions in the playlists need to resolve and map Source-IDs
1103 // also playlist needs to be merged or created with new-name..
1104 // ... and Diskstream in tracks adjusted to use the correct playlist
1105 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1106 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1107 child->add_child_nocopy ((*i)->get_state ());
1108 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1109 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1110 const Region::SourceList& sl = (*s)->sources ();
1111 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1112 sources.insert (*sli);
1117 child = node->add_child ("Sources");
1118 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1119 child->add_child_nocopy ((*i)->get_state ());
1120 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1122 #ifdef PLATFORM_WINDOWS
1125 string p = fs->path ();
1126 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1130 std::string sn = Glib::build_filename (path, "share.axml");
1133 tree.set_root (node);
1134 return tree.write (sn.c_str());
1139 struct route_id_compare {
1141 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1143 return r1->id () < r2->id ();
1149 Session::state (bool full_state, snapshot_t snapshot_type)
1152 XMLNode* node = new XMLNode("Session");
1155 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1157 child = node->add_child ("ProgramVersion");
1158 child->set_property("created-with", created_with);
1160 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1161 child->set_property("modified-with", modified_with);
1163 /* store configuration settings */
1167 node->set_property ("name", _name);
1168 node->set_property ("sample-rate", _base_frame_rate);
1170 if (session_dirs.size() > 1) {
1174 vector<space_and_path>::iterator i = session_dirs.begin();
1175 vector<space_and_path>::iterator next;
1177 ++i; /* skip the first one */
1181 while (i != session_dirs.end()) {
1185 if (next != session_dirs.end()) {
1186 p += G_SEARCHPATH_SEPARATOR;
1195 child = node->add_child ("Path");
1196 child->add_content (p);
1198 node->set_property ("end-is-free", _session_range_end_is_free);
1201 /* save the ID counter */
1203 node->set_property ("id-counter", ID::counter());
1205 node->set_property ("name-counter", name_id_counter ());
1207 /* save the event ID counter */
1209 node->set_property ("event-counter", Evoral::event_id_counter());
1211 /* save the VCA counter */
1213 node->set_property ("vca-counter", VCA::get_next_vca_number());
1215 /* various options */
1217 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1218 if (!midi_port_nodes.empty()) {
1219 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1220 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1221 midi_port_stuff->add_child_nocopy (**n);
1223 node->add_child_nocopy (*midi_port_stuff);
1226 XMLNode& cfgxml (config.get_variables ());
1228 /* exclude search-paths from template */
1229 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1230 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1231 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1233 node->add_child_nocopy (cfgxml);
1235 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1237 child = node->add_child ("Sources");
1240 Glib::Threads::Mutex::Lock sl (source_lock);
1242 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1244 /* Don't save information about non-file Sources, or
1245 * about non-destructive file sources that are empty
1246 * and unused by any regions.
1248 boost::shared_ptr<FileSource> fs;
1250 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1254 if (!fs->destructive()) {
1255 if (fs->empty() && !fs->used()) {
1260 if (snapshot_type != NormalSave && fs->within_session ()) {
1261 /* copy MIDI sources to new file
1263 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1264 * because the GUI (midi_region) has a direct pointer to the midi-model
1265 * of the source, as does UndoTransaction.
1267 * On the upside, .mid files are not kept open. The file is only open
1268 * when reading the model initially and when flushing the model to disk:
1269 * source->session_saved () or export.
1271 * We can change the _path of the existing source under the hood, keeping
1272 * all IDs, references and pointers intact.
1274 boost::shared_ptr<SMFSource> ms;
1275 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1276 const std::string ancestor_name = ms->ancestor_name();
1277 const std::string base = PBD::basename_nosuffix(ancestor_name);
1278 const string path = new_midi_source_path (base, false);
1280 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1281 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1282 Source::Lock lm (ms->mutex());
1284 // TODO special-case empty, removable() files: just create a new removable.
1285 // (load + write flushes the model and creates the file)
1287 ms->load_model (lm);
1289 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1290 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1292 if (snapshot_type == SnapshotKeep) {
1293 /* keep working on current session.
1295 * Save snapshot-state with the original filename.
1296 * Switch to use new path for future saves of the main session.
1298 child->add_child_nocopy (ms->get_state());
1302 * ~SMFSource unlinks removable() files.
1304 std::string npath (ms->path ());
1305 ms->replace_file (newsrc->path ());
1306 newsrc->replace_file (npath);
1308 if (snapshot_type == SwitchToSnapshot) {
1309 /* save and switch to snapshot.
1311 * Leave the old file in place (as is).
1312 * Snapshot uses new source directly
1314 child->add_child_nocopy (ms->get_state());
1321 child->add_child_nocopy (siter->second->get_state());
1325 child = node->add_child ("Regions");
1328 Glib::Threads::Mutex::Lock rl (region_lock);
1329 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1330 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1331 boost::shared_ptr<Region> r = i->second;
1332 /* only store regions not attached to playlists */
1333 if (r->playlist() == 0) {
1334 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1335 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1337 child->add_child_nocopy (r->get_state ());
1342 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1344 if (!cassocs.empty()) {
1345 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1347 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1348 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1349 can->set_property (X_("copy"), i->first->id());
1350 can->set_property (X_("original"), i->second->id());
1351 ca->add_child_nocopy (*can);
1358 node->add_child_nocopy (_selection->get_state());
1361 node->add_child_nocopy (_locations->get_state());
1364 Locations loc (*this);
1365 const bool was_dirty = dirty();
1366 // for a template, just create a new Locations, populate it
1367 // with the default start and end, and get the state for that.
1368 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1369 range->set (max_framepos, 0);
1371 XMLNode& locations_state = loc.get_state();
1373 if (ARDOUR::Profile->get_trx() && _locations) {
1374 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1375 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1376 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1377 locations_state.add_child_nocopy ((*i)->get_state ());
1381 node->add_child_nocopy (locations_state);
1383 /* adding a location above will have marked the session
1384 * dirty. This is an artifact, so fix it if the session wasn't
1389 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1393 child = node->add_child ("Bundles");
1395 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1396 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1397 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1399 child->add_child_nocopy (b->get_state());
1404 node->add_child_nocopy (_vca_manager->get_state());
1406 child = node->add_child ("Routes");
1408 boost::shared_ptr<RouteList> r = routes.reader ();
1410 route_id_compare cmp;
1411 RouteList xml_node_order (*r);
1412 xml_node_order.sort (cmp);
1414 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1415 if (!(*i)->is_auditioner()) {
1417 child->add_child_nocopy ((*i)->get_state());
1419 child->add_child_nocopy ((*i)->get_template());
1425 playlists->add_state (node, full_state);
1427 child = node->add_child ("RouteGroups");
1428 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1429 child->add_child_nocopy ((*i)->get_state());
1433 XMLNode* gain_child = node->add_child ("Click");
1434 gain_child->add_child_nocopy (_click_io->state (full_state));
1435 gain_child->add_child_nocopy (_click_gain->state (full_state));
1439 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1440 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1444 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1445 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1448 node->add_child_nocopy (_speakers->get_state());
1449 node->add_child_nocopy (_tempo_map->get_state());
1450 node->add_child_nocopy (get_control_protocol_state());
1453 node->add_child_copy (*_extra_xml);
1457 Glib::Threads::Mutex::Lock lm (lua_lock);
1460 luabridge::LuaRef savedstate ((*_lua_save)());
1461 saved = savedstate.cast<std::string>();
1463 lua.collect_garbage ();
1466 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1467 std::string b64s (b64);
1470 XMLNode* script_node = new XMLNode (X_("Script"));
1471 script_node->set_property (X_("lua"), LUA_VERSION);
1472 script_node->add_content (b64s);
1473 node->add_child_nocopy (*script_node);
1480 Session::get_control_protocol_state ()
1482 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1483 return cpm.get_state();
1487 Session::set_state (const XMLNode& node, int version)
1494 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1496 if (node.name() != X_("Session")) {
1497 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1501 node.get_property ("name", _name);
1503 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1505 _nominal_frame_rate = _base_frame_rate;
1507 assert (AudioEngine::instance()->running ());
1508 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1509 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1510 if (r.get_value_or (0)) {
1516 created_with = "unknown";
1517 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1518 child->get_property (X_("created-with"), created_with);
1521 setup_raid_path(_session_dir->root_path());
1523 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1526 if (node.get_property (X_("id-counter"), counter)) {
1527 ID::init_counter (counter);
1529 /* old sessions used a timebased counter, so fake
1530 * the startup ID counter based on a standard
1535 ID::init_counter (now);
1538 if (node.get_property (X_("name-counter"), counter)) {
1539 init_name_id_counter (counter);
1542 if (node.get_property (X_("event-counter"), counter)) {
1543 Evoral::init_event_id_counter (counter);
1546 if (node.get_property (X_("vca-counter"), counter)) {
1547 VCA::set_next_vca_number (counter);
1549 VCA::set_next_vca_number (1);
1552 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1553 _midi_ports->set_midi_port_states (child->children());
1556 IO::disable_connecting ();
1558 Stateful::save_extra_xml (node);
1560 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1561 load_options (*child);
1562 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1563 load_options (*child);
1565 error << _("Session: XML state has no options section") << endmsg;
1568 if (version >= 3000) {
1569 if ((child = find_named_node (node, "Metadata")) == 0) {
1570 warning << _("Session: XML state has no metadata section") << endmsg;
1571 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1576 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1577 _speakers->set_state (*child, version);
1580 if ((child = find_named_node (node, "Sources")) == 0) {
1581 error << _("Session: XML state has no sources section") << endmsg;
1583 } else if (load_sources (*child)) {
1587 if ((child = find_named_node (node, "TempoMap")) == 0) {
1588 error << _("Session: XML state has no Tempo Map section") << endmsg;
1590 } else if (_tempo_map->set_state (*child, version)) {
1594 if ((child = find_named_node (node, "Locations")) == 0) {
1595 error << _("Session: XML state has no locations section") << endmsg;
1597 } else if (_locations->set_state (*child, version)) {
1601 locations_changed ();
1603 if (_session_range_location) {
1604 AudioFileSource::set_header_position_offset (_session_range_location->start());
1607 if ((child = find_named_node (node, "Regions")) == 0) {
1608 error << _("Session: XML state has no Regions section") << endmsg;
1610 } else if (load_regions (*child)) {
1614 if ((child = find_named_node (node, "Playlists")) == 0) {
1615 error << _("Session: XML state has no playlists section") << endmsg;
1617 } else if (playlists->load (*this, *child)) {
1621 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1623 } else if (playlists->load_unused (*this, *child)) {
1627 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1628 if (load_compounds (*child)) {
1633 if (version >= 3000) {
1634 if ((child = find_named_node (node, "Bundles")) == 0) {
1635 warning << _("Session: XML state has no bundles section") << endmsg;
1638 /* We can't load Bundles yet as they need to be able
1639 * to convert from port names to Port objects, which can't happen until
1641 _bundle_xml_node = new XMLNode (*child);
1645 if (version < 3000) {
1646 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1647 error << _("Session: XML state has no diskstreams section") << endmsg;
1649 } else if (load_diskstreams_2X (*child, version)) {
1654 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1655 _vca_manager->set_state (*child, version);
1658 if ((child = find_named_node (node, "Routes")) == 0) {
1659 error << _("Session: XML state has no routes section") << endmsg;
1661 } else if (load_routes (*child, version)) {
1665 /* Now that we have Routes and masters loaded, connect them if appropriate */
1667 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1669 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1670 _diskstreams_2X.clear ();
1672 if (version >= 3000) {
1674 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1675 error << _("Session: XML state has no route groups section") << endmsg;
1677 } else if (load_route_groups (*child, version)) {
1681 } else if (version < 3000) {
1683 if ((child = find_named_node (node, "EditGroups")) == 0) {
1684 error << _("Session: XML state has no edit groups section") << endmsg;
1686 } else if (load_route_groups (*child, version)) {
1690 if ((child = find_named_node (node, "MixGroups")) == 0) {
1691 error << _("Session: XML state has no mix groups section") << endmsg;
1693 } else if (load_route_groups (*child, version)) {
1698 if ((child = find_named_node (node, "Click")) == 0) {
1699 warning << _("Session: XML state has no click section") << endmsg;
1700 } else if (_click_io) {
1701 setup_click_state (&node);
1704 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1705 ControlProtocolManager::instance().set_state (*child, version);
1708 if ((child = find_named_node (node, "Script"))) {
1709 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1710 if (!(*n)->is_content ()) { continue; }
1712 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1714 Glib::Threads::Mutex::Lock lm (lua_lock);
1715 (*_lua_load)(std::string ((const char*)buf, size));
1716 } catch (luabridge::LuaException const& e) {
1717 cerr << "LuaException:" << e.what () << endl;
1723 if ((child = find_named_node (node, X_("Selection")))) {
1724 _selection->set_state (*child, version);
1727 update_route_record_state ();
1729 /* here beginneth the second phase ... */
1730 set_snapshot_name (_current_snapshot_name);
1732 StateReady (); /* EMIT SIGNAL */
1745 Session::load_routes (const XMLNode& node, int version)
1748 XMLNodeConstIterator niter;
1749 RouteList new_routes;
1751 nlist = node.children();
1755 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1757 boost::shared_ptr<Route> route;
1758 if (version < 3000) {
1759 route = XMLRouteFactory_2X (**niter, version);
1761 route = XMLRouteFactory (**niter, version);
1765 error << _("Session: cannot create Route from XML description.") << endmsg;
1769 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1771 new_routes.push_back (route);
1774 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1776 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1778 BootMessage (_("Finished adding tracks/busses"));
1783 boost::shared_ptr<Route>
1784 Session::XMLRouteFactory (const XMLNode& node, int version)
1786 boost::shared_ptr<Route> ret;
1788 if (node.name() != "Route") {
1792 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1794 DataType type = DataType::AUDIO;
1795 node.get_property("default-type", type);
1797 assert (type != DataType::NIL);
1801 boost::shared_ptr<Track> track;
1803 if (type == DataType::AUDIO) {
1804 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1806 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1809 if (track->init()) {
1813 if (track->set_state (node, version)) {
1817 BOOST_MARK_TRACK (track);
1821 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1822 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1824 if (r->init () == 0 && r->set_state (node, version) == 0) {
1825 BOOST_MARK_ROUTE (r);
1833 boost::shared_ptr<Route>
1834 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1836 boost::shared_ptr<Route> ret;
1838 if (node.name() != "Route") {
1842 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1844 ds_prop = node.property (X_("diskstream"));
1847 DataType type = DataType::AUDIO;
1848 node.get_property("default-type", type);
1850 assert (type != DataType::NIL);
1854 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1855 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1859 if (i == _diskstreams_2X.end()) {
1860 error << _("Could not find diskstream for route") << endmsg;
1861 return boost::shared_ptr<Route> ();
1864 boost::shared_ptr<Track> track;
1866 if (type == DataType::AUDIO) {
1867 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1869 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1872 if (track->init()) {
1876 if (track->set_state (node, version)) {
1880 track->set_diskstream (*i);
1882 BOOST_MARK_TRACK (track);
1886 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1887 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1889 if (r->init () == 0 && r->set_state (node, version) == 0) {
1890 BOOST_MARK_ROUTE (r);
1899 Session::load_regions (const XMLNode& node)
1902 XMLNodeConstIterator niter;
1903 boost::shared_ptr<Region> region;
1905 nlist = node.children();
1909 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1910 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1911 error << _("Session: cannot create Region from XML description.");
1912 XMLProperty const * name = (**niter).property("name");
1915 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1926 Session::load_compounds (const XMLNode& node)
1928 XMLNodeList calist = node.children();
1929 XMLNodeConstIterator caiter;
1930 XMLProperty const * caprop;
1932 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1933 XMLNode* ca = *caiter;
1937 if ((caprop = ca->property (X_("original"))) == 0) {
1940 orig_id = caprop->value();
1942 if ((caprop = ca->property (X_("copy"))) == 0) {
1945 copy_id = caprop->value();
1947 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1948 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1950 if (!orig || !copy) {
1951 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1957 RegionFactory::add_compound_association (orig, copy);
1964 Session::load_nested_sources (const XMLNode& node)
1967 XMLNodeConstIterator niter;
1969 nlist = node.children();
1971 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1972 if ((*niter)->name() == "Source") {
1974 /* it may already exist, so don't recreate it unnecessarily
1977 XMLProperty const * prop = (*niter)->property (X_("id"));
1979 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1983 ID source_id (prop->value());
1985 if (!source_by_id (source_id)) {
1988 SourceFactory::create (*this, **niter, true);
1990 catch (failed_constructor& err) {
1991 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1998 boost::shared_ptr<Region>
1999 Session::XMLRegionFactory (const XMLNode& node, bool full)
2001 XMLProperty const * type = node.property("type");
2005 const XMLNodeList& nlist = node.children();
2007 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2008 XMLNode *child = (*niter);
2009 if (child->name() == "NestedSource") {
2010 load_nested_sources (*child);
2014 if (!type || type->value() == "audio") {
2015 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2016 } else if (type->value() == "midi") {
2017 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2020 } catch (failed_constructor& err) {
2021 return boost::shared_ptr<Region> ();
2024 return boost::shared_ptr<Region> ();
2027 boost::shared_ptr<AudioRegion>
2028 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2030 XMLProperty const * prop;
2031 boost::shared_ptr<Source> source;
2032 boost::shared_ptr<AudioSource> as;
2034 SourceList master_sources;
2035 uint32_t nchans = 1;
2038 if (node.name() != X_("Region")) {
2039 return boost::shared_ptr<AudioRegion>();
2042 node.get_property (X_("channels"), nchans);
2044 if ((prop = node.property ("name")) == 0) {
2045 cerr << "no name for this region\n";
2049 if ((prop = node.property (X_("source-0"))) == 0) {
2050 if ((prop = node.property ("source")) == 0) {
2051 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2052 return boost::shared_ptr<AudioRegion>();
2056 PBD::ID s_id (prop->value());
2058 if ((source = source_by_id (s_id)) == 0) {
2059 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2060 return boost::shared_ptr<AudioRegion>();
2063 as = boost::dynamic_pointer_cast<AudioSource>(source);
2065 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2066 return boost::shared_ptr<AudioRegion>();
2069 sources.push_back (as);
2071 /* pickup other channels */
2073 for (uint32_t n=1; n < nchans; ++n) {
2074 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2075 if ((prop = node.property (buf)) != 0) {
2077 PBD::ID id2 (prop->value());
2079 if ((source = source_by_id (id2)) == 0) {
2080 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2081 return boost::shared_ptr<AudioRegion>();
2084 as = boost::dynamic_pointer_cast<AudioSource>(source);
2086 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2087 return boost::shared_ptr<AudioRegion>();
2089 sources.push_back (as);
2093 for (uint32_t n = 0; n < nchans; ++n) {
2094 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2095 if ((prop = node.property (buf)) != 0) {
2097 PBD::ID id2 (prop->value());
2099 if ((source = source_by_id (id2)) == 0) {
2100 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2101 return boost::shared_ptr<AudioRegion>();
2104 as = boost::dynamic_pointer_cast<AudioSource>(source);
2106 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2107 return boost::shared_ptr<AudioRegion>();
2109 master_sources.push_back (as);
2114 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2116 /* a final detail: this is the one and only place that we know how long missing files are */
2118 if (region->whole_file()) {
2119 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2120 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2122 sfp->set_length (region->length());
2127 if (!master_sources.empty()) {
2128 if (master_sources.size() != nchans) {
2129 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2131 region->set_master_sources (master_sources);
2139 catch (failed_constructor& err) {
2140 return boost::shared_ptr<AudioRegion>();
2144 boost::shared_ptr<MidiRegion>
2145 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2147 XMLProperty const * prop;
2148 boost::shared_ptr<Source> source;
2149 boost::shared_ptr<MidiSource> ms;
2152 if (node.name() != X_("Region")) {
2153 return boost::shared_ptr<MidiRegion>();
2156 if ((prop = node.property ("name")) == 0) {
2157 cerr << "no name for this region\n";
2161 if ((prop = node.property (X_("source-0"))) == 0) {
2162 if ((prop = node.property ("source")) == 0) {
2163 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2164 return boost::shared_ptr<MidiRegion>();
2168 PBD::ID s_id (prop->value());
2170 if ((source = source_by_id (s_id)) == 0) {
2171 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2172 return boost::shared_ptr<MidiRegion>();
2175 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2177 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2178 return boost::shared_ptr<MidiRegion>();
2181 sources.push_back (ms);
2184 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2185 /* a final detail: this is the one and only place that we know how long missing files are */
2187 if (region->whole_file()) {
2188 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2189 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2191 sfp->set_length (region->length());
2199 catch (failed_constructor& err) {
2200 return boost::shared_ptr<MidiRegion>();
2205 Session::get_sources_as_xml ()
2208 XMLNode* node = new XMLNode (X_("Sources"));
2209 Glib::Threads::Mutex::Lock lm (source_lock);
2211 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2212 node->add_child_nocopy (i->second->get_state());
2219 Session::reset_write_sources (bool mark_write_complete, bool force)
2221 boost::shared_ptr<RouteList> rl = routes.reader();
2222 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2223 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2225 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2226 tr->reset_write_sources(mark_write_complete, force);
2227 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2233 Session::load_sources (const XMLNode& node)
2236 XMLNodeConstIterator niter;
2237 /* don't need this but it stops some
2238 * versions of gcc complaining about
2239 * discarded return values.
2241 boost::shared_ptr<Source> source;
2243 nlist = node.children();
2246 std::map<std::string, std::string> relocation;
2248 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2249 #ifdef PLATFORM_WINDOWS
2253 XMLNode srcnode (**niter);
2254 bool try_replace_abspath = true;
2258 #ifdef PLATFORM_WINDOWS
2259 // do not show "insert media" popups (files embedded from removable media).
2260 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2262 if ((source = XMLSourceFactory (srcnode)) == 0) {
2263 error << _("Session: cannot create Source from XML description.") << endmsg;
2265 #ifdef PLATFORM_WINDOWS
2266 SetErrorMode(old_mode);
2269 } catch (MissingSource& err) {
2270 #ifdef PLATFORM_WINDOWS
2271 SetErrorMode(old_mode);
2274 /* try previous abs path replacements first */
2275 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2276 std::string dir = Glib::path_get_dirname (err.path);
2277 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2278 if (rl != relocation.end ()) {
2279 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2280 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2281 srcnode.set_property ("origin", newpath);
2282 try_replace_abspath = false;
2289 _missing_file_replacement = "";
2291 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2292 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2293 PROGRAM_NAME) << endmsg;
2297 if (!no_questions_about_missing_files) {
2298 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2303 switch (user_choice) {
2305 /* user added a new search location
2306 * or selected a new absolute path,
2308 if (Glib::path_is_absolute (err.path)) {
2309 if (!_missing_file_replacement.empty ()) {
2310 /* replace origin, in XML */
2311 std::string newpath = Glib::build_filename (
2312 _missing_file_replacement, Glib::path_get_basename (err.path));
2313 srcnode.set_property ("origin", newpath);
2314 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2315 _missing_file_replacement = "";
2322 /* user asked to quit the entire session load */
2326 no_questions_about_missing_files = true;
2330 no_questions_about_missing_files = true;
2337 case DataType::AUDIO:
2338 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2341 case DataType::MIDI:
2342 /* The MIDI file is actually missing so
2343 * just create a new one in the same
2344 * location. Do not announce its
2348 if (!Glib::path_is_absolute (err.path)) {
2349 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2351 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2356 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2357 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2358 /* reset ID to match the missing one */
2359 source->set_id (**niter);
2360 /* Now we can announce it */
2361 SourceFactory::SourceCreated (source);
2372 boost::shared_ptr<Source>
2373 Session::XMLSourceFactory (const XMLNode& node)
2375 if (node.name() != "Source") {
2376 return boost::shared_ptr<Source>();
2380 /* note: do peak building in another thread when loading session state */
2381 return SourceFactory::create (*this, node, true);
2384 catch (failed_constructor& err) {
2385 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2386 return boost::shared_ptr<Source>();
2391 Session::save_template (string template_name, bool replace_existing)
2393 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2397 bool absolute_path = Glib::path_is_absolute (template_name);
2399 /* directory to put the template in */
2400 std::string template_dir_path;
2402 if (!absolute_path) {
2403 std::string user_template_dir(user_template_directory());
2405 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2406 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2407 user_template_dir, g_strerror (errno)) << endmsg;
2411 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2413 template_dir_path = template_name;
2416 if (!ARDOUR::Profile->get_trx()) {
2417 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2418 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2419 template_dir_path) << endmsg;
2423 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2424 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2425 template_dir_path, g_strerror (errno)) << endmsg;
2431 std::string template_file_path;
2433 if (ARDOUR::Profile->get_trx()) {
2434 template_file_path = template_name;
2436 if (absolute_path) {
2437 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2439 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2443 SessionSaveUnderway (); /* EMIT SIGNAL */
2448 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2449 tree.set_root (&get_template());
2452 if (!tree.write (template_file_path)) {
2453 error << _("template not saved") << endmsg;
2457 store_recent_templates (template_file_path);
2463 Session::refresh_disk_space ()
2465 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2467 Glib::Threads::Mutex::Lock lm (space_lock);
2469 /* get freespace on every FS that is part of the session path */
2471 _total_free_4k_blocks = 0;
2472 _total_free_4k_blocks_uncertain = false;
2474 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2475 #if defined(__NetBSD__)
2476 struct statvfs statfsbuf;
2478 statvfs (i->path.c_str(), &statfsbuf);
2480 struct statfs statfsbuf;
2482 statfs (i->path.c_str(), &statfsbuf);
2484 double const scale = statfsbuf.f_bsize / 4096.0;
2486 /* See if this filesystem is read-only */
2487 struct statvfs statvfsbuf;
2488 statvfs (i->path.c_str(), &statvfsbuf);
2490 /* f_bavail can be 0 if it is undefined for whatever
2491 filesystem we are looking at; Samba shares mounted
2492 via GVFS are an example of this.
2494 if (statfsbuf.f_bavail == 0) {
2495 /* block count unknown */
2497 i->blocks_unknown = true;
2498 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2499 /* read-only filesystem */
2501 i->blocks_unknown = false;
2503 /* read/write filesystem with known space */
2504 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2505 i->blocks_unknown = false;
2508 _total_free_4k_blocks += i->blocks;
2509 if (i->blocks_unknown) {
2510 _total_free_4k_blocks_uncertain = true;
2513 #elif defined PLATFORM_WINDOWS
2514 vector<string> scanned_volumes;
2515 vector<string>::iterator j;
2516 vector<space_and_path>::iterator i;
2517 DWORD nSectorsPerCluster, nBytesPerSector,
2518 nFreeClusters, nTotalClusters;
2522 _total_free_4k_blocks = 0;
2524 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2525 strncpy (disk_drive, (*i).path.c_str(), 3);
2529 volume_found = false;
2530 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2532 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2533 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2534 i->blocks = (uint32_t)(nFreeBytes / 4096);
2536 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2537 if (0 == j->compare(disk_drive)) {
2538 volume_found = true;
2543 if (!volume_found) {
2544 scanned_volumes.push_back(disk_drive);
2545 _total_free_4k_blocks += i->blocks;
2550 if (0 == _total_free_4k_blocks) {
2551 strncpy (disk_drive, path().c_str(), 3);
2554 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2556 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2557 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2558 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2565 Session::get_best_session_directory_for_new_audio ()
2567 vector<space_and_path>::iterator i;
2568 string result = _session_dir->root_path();
2570 /* handle common case without system calls */
2572 if (session_dirs.size() == 1) {
2576 /* OK, here's the algorithm we're following here:
2578 We want to select which directory to use for
2579 the next file source to be created. Ideally,
2580 we'd like to use a round-robin process so as to
2581 get maximum performance benefits from splitting
2582 the files across multiple disks.
2584 However, in situations without much diskspace, an
2585 RR approach may end up filling up a filesystem
2586 with new files while others still have space.
2587 Its therefore important to pay some attention to
2588 the freespace in the filesystem holding each
2589 directory as well. However, if we did that by
2590 itself, we'd keep creating new files in the file
2591 system with the most space until it was as full
2592 as all others, thus negating any performance
2593 benefits of this RAID-1 like approach.
2595 So, we use a user-configurable space threshold. If
2596 there are at least 2 filesystems with more than this
2597 much space available, we use RR selection between them.
2598 If not, then we pick the filesystem with the most space.
2600 This gets a good balance between the two
2604 refresh_disk_space ();
2606 int free_enough = 0;
2608 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2609 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2614 if (free_enough >= 2) {
2615 /* use RR selection process, ensuring that the one
2619 i = last_rr_session_dir;
2622 if (++i == session_dirs.end()) {
2623 i = session_dirs.begin();
2626 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2627 SessionDirectory sdir(i->path);
2628 if (sdir.create ()) {
2630 last_rr_session_dir = i;
2635 } while (i != last_rr_session_dir);
2639 /* pick FS with the most freespace (and that
2640 seems to actually work ...)
2643 vector<space_and_path> sorted;
2644 space_and_path_ascending_cmp cmp;
2646 sorted = session_dirs;
2647 sort (sorted.begin(), sorted.end(), cmp);
2649 for (i = sorted.begin(); i != sorted.end(); ++i) {
2650 SessionDirectory sdir(i->path);
2651 if (sdir.create ()) {
2653 last_rr_session_dir = i;
2663 Session::automation_dir () const
2665 return Glib::build_filename (_path, automation_dir_name);
2669 Session::analysis_dir () const
2671 return Glib::build_filename (_path, analysis_dir_name);
2675 Session::plugins_dir () const
2677 return Glib::build_filename (_path, plugins_dir_name);
2681 Session::externals_dir () const
2683 return Glib::build_filename (_path, externals_dir_name);
2687 Session::load_bundles (XMLNode const & node)
2689 XMLNodeList nlist = node.children();
2690 XMLNodeConstIterator niter;
2694 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2695 if ((*niter)->name() == "InputBundle") {
2696 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2697 } else if ((*niter)->name() == "OutputBundle") {
2698 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2700 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2709 Session::load_route_groups (const XMLNode& node, int version)
2711 XMLNodeList nlist = node.children();
2712 XMLNodeConstIterator niter;
2716 if (version >= 3000) {
2718 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2719 if ((*niter)->name() == "RouteGroup") {
2720 RouteGroup* rg = new RouteGroup (*this, "");
2721 add_route_group (rg);
2722 rg->set_state (**niter, version);
2726 } else if (version < 3000) {
2728 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2729 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2730 RouteGroup* rg = new RouteGroup (*this, "");
2731 add_route_group (rg);
2732 rg->set_state (**niter, version);
2741 state_file_filter (const string &str, void* /*arg*/)
2743 return (str.length() > strlen(statefile_suffix) &&
2744 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2748 remove_end(string state)
2750 string statename(state);
2752 string::size_type start,end;
2753 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2754 statename = statename.substr (start+1);
2757 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2758 end = statename.length();
2761 return string(statename.substr (0, end));
2765 Session::possible_states (string path)
2767 vector<string> states;
2768 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2770 transform(states.begin(), states.end(), states.begin(), remove_end);
2772 sort (states.begin(), states.end());
2778 Session::possible_states () const
2780 return possible_states(_path);
2784 Session::new_route_group (const std::string& name)
2786 RouteGroup* rg = NULL;
2788 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2789 if ((*i)->name () == name) {
2796 rg = new RouteGroup (*this, name);
2797 add_route_group (rg);
2803 Session::add_route_group (RouteGroup* g)
2805 _route_groups.push_back (g);
2806 route_group_added (g); /* EMIT SIGNAL */
2808 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2809 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2810 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2816 Session::remove_route_group (RouteGroup& rg)
2818 list<RouteGroup*>::iterator i;
2820 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2821 _route_groups.erase (i);
2824 route_group_removed (); /* EMIT SIGNAL */
2828 /** Set a new order for our route groups, without adding or removing any.
2829 * @param groups Route group list in the new order.
2832 Session::reorder_route_groups (list<RouteGroup*> groups)
2834 _route_groups = groups;
2836 route_groups_reordered (); /* EMIT SIGNAL */
2842 Session::route_group_by_name (string name)
2844 list<RouteGroup *>::iterator i;
2846 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2847 if ((*i)->name() == name) {
2855 Session::all_route_group() const
2857 return *_all_route_group;
2861 Session::add_commands (vector<Command*> const & cmds)
2863 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2869 Session::add_command (Command* const cmd)
2871 assert (_current_trans);
2872 DEBUG_UNDO_HISTORY (
2873 string_compose ("Current Undo Transaction %1, adding command: %2",
2874 _current_trans->name (),
2876 _current_trans->add_command (cmd);
2879 PBD::StatefulDiffCommand*
2880 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2882 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2888 Session::begin_reversible_command (const string& name)
2890 begin_reversible_command (g_quark_from_string (name.c_str ()));
2893 /** Begin a reversible command using a GQuark to identify it.
2894 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2895 * but there must be as many begin...()s as there are commit...()s.
2898 Session::begin_reversible_command (GQuark q)
2900 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2901 to hold all the commands that are committed. This keeps the order of
2902 commands correct in the history.
2905 if (_current_trans == 0) {
2906 DEBUG_UNDO_HISTORY (string_compose (
2907 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2909 /* start a new transaction */
2910 assert (_current_trans_quarks.empty ());
2911 _current_trans = new UndoTransaction();
2912 _current_trans->set_name (g_quark_to_string (q));
2914 DEBUG_UNDO_HISTORY (
2915 string_compose ("Begin Reversible Command, current transaction: %1",
2916 _current_trans->name ()));
2919 _current_trans_quarks.push_front (q);
2923 Session::abort_reversible_command ()
2925 if (_current_trans != 0) {
2926 DEBUG_UNDO_HISTORY (
2927 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2928 _current_trans->clear();
2929 delete _current_trans;
2931 _current_trans_quarks.clear();
2936 Session::commit_reversible_command (Command *cmd)
2938 assert (_current_trans);
2939 assert (!_current_trans_quarks.empty ());
2944 DEBUG_UNDO_HISTORY (
2945 string_compose ("Current Undo Transaction %1, adding command: %2",
2946 _current_trans->name (),
2948 _current_trans->add_command (cmd);
2951 DEBUG_UNDO_HISTORY (
2952 string_compose ("Commit Reversible Command, current transaction: %1",
2953 _current_trans->name ()));
2955 _current_trans_quarks.pop_front ();
2957 if (!_current_trans_quarks.empty ()) {
2958 DEBUG_UNDO_HISTORY (
2959 string_compose ("Commit Reversible Command, transaction is not "
2960 "top-level, current transaction: %1",
2961 _current_trans->name ()));
2962 /* the transaction we're committing is not the top-level one */
2966 if (_current_trans->empty()) {
2967 /* no commands were added to the transaction, so just get rid of it */
2968 DEBUG_UNDO_HISTORY (
2969 string_compose ("Commit Reversible Command, No commands were "
2970 "added to current transaction: %1",
2971 _current_trans->name ()));
2972 delete _current_trans;
2977 gettimeofday (&now, 0);
2978 _current_trans->set_timestamp (now);
2980 _history.add (_current_trans);
2985 accept_all_audio_files (const string& path, void* /*arg*/)
2987 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2991 if (!AudioFileSource::safe_audio_file_extension (path)) {
2999 accept_all_midi_files (const string& path, void* /*arg*/)
3001 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3005 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3006 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3007 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3011 accept_all_state_files (const string& path, void* /*arg*/)
3013 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3017 std::string const statefile_ext (statefile_suffix);
3018 if (path.length() >= statefile_ext.length()) {
3019 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3026 Session::find_all_sources (string path, set<string>& result)
3031 if (!tree.read (path)) {
3035 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3040 XMLNodeConstIterator niter;
3042 nlist = node->children();
3046 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3048 XMLProperty const * prop;
3050 if ((prop = (*niter)->property (X_("type"))) == 0) {
3054 DataType type (prop->value());
3056 if ((prop = (*niter)->property (X_("name"))) == 0) {
3060 if (Glib::path_is_absolute (prop->value())) {
3061 /* external file, ignore */
3069 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3070 result.insert (found_path);
3078 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3080 vector<string> state_files;
3082 string this_snapshot_path;
3088 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3089 ripped = ripped.substr (0, ripped.length() - 1);
3092 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3094 if (state_files.empty()) {
3099 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3100 this_snapshot_path += statefile_suffix;
3102 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3104 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3106 if (exclude_this_snapshot && *i == this_snapshot_path) {
3107 cerr << "\texcluded\n";
3112 if (find_all_sources (*i, result) < 0) {
3120 struct RegionCounter {
3121 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3122 AudioSourceList::iterator iter;
3123 boost::shared_ptr<Region> region;
3126 RegionCounter() : count (0) {}
3130 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3132 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3133 return r.get_value_or (1);
3137 Session::cleanup_regions ()
3139 bool removed = false;
3140 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3142 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3144 uint32_t used = playlists->region_use_count (i->second);
3146 if (used == 0 && !i->second->automatic ()) {
3147 boost::weak_ptr<Region> w = i->second;
3150 RegionFactory::map_remove (w);
3157 // re-check to remove parent references of compound regions
3158 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3159 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3163 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3164 if (0 == playlists->region_use_count (i->second)) {
3165 boost::weak_ptr<Region> w = i->second;
3167 RegionFactory::map_remove (w);
3174 /* dump the history list */
3181 Session::can_cleanup_peakfiles () const
3183 if (deletion_in_progress()) {
3186 if (!_writable || (_state_of_the_state & CannotSave)) {
3187 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3190 if (record_status() == Recording) {
3191 error << _("Cannot cleanup peak-files while recording") << endmsg;
3198 Session::cleanup_peakfiles ()
3200 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3205 assert (can_cleanup_peakfiles ());
3206 assert (!peaks_cleanup_in_progres());
3208 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3210 int timeout = 5000; // 5 seconds
3211 while (!SourceFactory::files_with_peaks.empty()) {
3212 Glib::usleep (1000);
3213 if (--timeout < 0) {
3214 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3215 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3220 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3221 boost::shared_ptr<AudioSource> as;
3222 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3223 as->close_peakfile();
3227 PBD::clear_directory (session_directory().peak_path());
3229 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3231 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3232 boost::shared_ptr<AudioSource> as;
3233 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3234 SourceFactory::setup_peakfile(as, true);
3241 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3243 pl->deep_sources (*all_sources);
3247 Session::cleanup_sources (CleanupReport& rep)
3249 // FIXME: needs adaptation to midi
3251 vector<boost::shared_ptr<Source> > dead_sources;
3254 vector<string> candidates;
3255 vector<string> unused;
3256 set<string> sources_used_by_all_snapshots;
3263 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3265 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3267 /* this is mostly for windows which doesn't allow file
3268 * renaming if the file is in use. But we don't special
3269 * case it because we need to know if this causes
3270 * problems, and the easiest way to notice that is to
3271 * keep it in place for all platforms.
3274 request_stop (false);
3276 _butler->wait_until_finished ();
3278 /* consider deleting all unused playlists */
3280 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3285 /* sync the "all regions" property of each playlist with its current state */
3287 playlists->sync_all_regions_with_regions ();
3289 /* find all un-used sources */
3294 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3296 SourceMap::iterator tmp;
3301 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3305 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3306 dead_sources.push_back (i->second);
3307 i->second->drop_references ();
3313 /* build a list of all the possible audio directories for the session */
3315 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3316 SessionDirectory sdir ((*i).path);
3317 asp += sdir.sound_path();
3319 audio_path += asp.to_string();
3322 /* build a list of all the possible midi directories for the session */
3324 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3325 SessionDirectory sdir ((*i).path);
3326 msp += sdir.midi_path();
3328 midi_path += msp.to_string();
3330 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3331 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3333 /* add sources from all other snapshots as "used", but don't use this
3334 snapshot because the state file on disk still references sources we
3335 may have already dropped.
3338 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3340 /* Although the region factory has a list of all regions ever created
3341 * for this session, we're only interested in regions actually in
3342 * playlists right now. So merge all playlist regions lists together.
3344 * This will include the playlists used within compound regions.
3347 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3349 /* add our current source list
3352 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3353 boost::shared_ptr<FileSource> fs;
3354 SourceMap::iterator tmp = i;
3357 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3363 /* this is mostly for windows which doesn't allow file
3364 * renaming if the file is in use. But we do not special
3365 * case it because we need to know if this causes
3366 * problems, and the easiest way to notice that is to
3367 * keep it in place for all platforms.
3372 if (!fs->is_stub()) {
3374 /* Note that we're checking a list of all
3375 * sources across all snapshots with the list
3376 * of sources used by this snapshot.
3379 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3380 /* this source is in use by this snapshot */
3381 sources_used_by_all_snapshots.insert (fs->path());
3382 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3384 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3385 /* this source is NOT in use by this snapshot */
3387 /* remove all related regions from RegionFactory master list */
3389 RegionFactory::remove_regions_using_source (i->second);
3391 /* remove from our current source list
3392 * also. We may not remove it from
3393 * disk, because it may be used by
3394 * other snapshots, but it isn't used inside this
3395 * snapshot anymore, so we don't need a
3406 /* now check each candidate source to see if it exists in the list of
3407 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3410 cerr << "Candidates: " << candidates.size() << endl;
3411 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3413 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3418 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3420 tmppath1 = canonical_path (spath);
3421 tmppath2 = canonical_path ((*i));
3423 cerr << "\t => " << tmppath2 << endl;
3425 if (tmppath1 == tmppath2) {
3432 unused.push_back (spath);
3436 cerr << "Actually unused: " << unused.size() << endl;
3438 if (unused.empty()) {
3444 /* now try to move all unused files into the "dead" directory(ies) */
3446 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3451 /* don't move the file across filesystems, just
3452 * stick it in the `dead_dir_name' directory
3453 * on whichever filesystem it was already on.
3456 if ((*x).find ("/sounds/") != string::npos) {
3458 /* old school, go up 1 level */
3460 newpath = Glib::path_get_dirname (*x); // "sounds"
3461 newpath = Glib::path_get_dirname (newpath); // "session-name"
3465 /* new school, go up 4 levels */
3467 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3468 newpath = Glib::path_get_dirname (newpath); // "session-name"
3469 newpath = Glib::path_get_dirname (newpath); // "interchange"
3470 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3473 newpath = Glib::build_filename (newpath, dead_dir_name);
3475 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3476 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3480 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3482 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3484 /* the new path already exists, try versioning */
3486 char buf[PATH_MAX+1];
3490 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3493 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3494 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3498 if (version == 999) {
3499 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3503 newpath = newpath_v;
3508 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3509 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3510 newpath, g_strerror (errno)) << endmsg;
3514 /* see if there an easy to find peakfile for this file, and remove it. */
3516 string base = Glib::path_get_basename (*x);
3517 base += "%A"; /* this is what we add for the channel suffix of all native files,
3518 * or for the first channel of embedded files. it will miss
3519 * some peakfiles for other channels
3521 string peakpath = construct_peak_filepath (base);
3523 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3524 if (::g_unlink (peakpath.c_str ()) != 0) {
3525 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3526 g_strerror (errno)) << endmsg;
3527 /* try to back out */
3528 ::g_rename (newpath.c_str (), _path.c_str ());
3533 rep.paths.push_back (*x);
3534 rep.space += statbuf.st_size;
3537 /* dump the history list */
3541 /* save state so we don't end up a session file
3542 * referring to non-existent sources.
3549 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3555 Session::cleanup_trash_sources (CleanupReport& rep)
3557 // FIXME: needs adaptation for MIDI
3559 vector<space_and_path>::iterator i;
3565 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3567 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3569 clear_directory (dead_dir, &rep.space, &rep.paths);
3576 Session::set_dirty ()
3578 /* return early if there's nothing to do */
3583 /* never mark session dirty during loading */
3584 if (_state_of_the_state & Loading) {
3588 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3589 DirtyChanged(); /* EMIT SIGNAL */
3593 Session::set_clean ()
3595 bool was_dirty = dirty();
3597 _state_of_the_state = Clean;
3600 DirtyChanged(); /* EMIT SIGNAL */
3605 Session::set_deletion_in_progress ()
3607 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3611 Session::clear_deletion_in_progress ()
3613 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3617 Session::add_controllable (boost::shared_ptr<Controllable> c)
3619 /* this adds a controllable to the list managed by the Session.
3620 this is a subset of those managed by the Controllable class
3621 itself, and represents the only ones whose state will be saved
3622 as part of the session.
3625 Glib::Threads::Mutex::Lock lm (controllables_lock);
3626 controllables.insert (c);
3629 struct null_deleter { void operator()(void const *) const {} };
3632 Session::remove_controllable (Controllable* c)
3634 if (_state_of_the_state & Deletion) {
3638 Glib::Threads::Mutex::Lock lm (controllables_lock);
3640 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3642 if (x != controllables.end()) {
3643 controllables.erase (x);
3647 boost::shared_ptr<Controllable>
3648 Session::controllable_by_id (const PBD::ID& id)
3650 Glib::Threads::Mutex::Lock lm (controllables_lock);
3652 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3653 if ((*i)->id() == id) {
3658 return boost::shared_ptr<Controllable>();
3661 boost::shared_ptr<AutomationControl>
3662 Session::automation_control_by_id (const PBD::ID& id)
3664 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3667 boost::shared_ptr<Controllable>
3668 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3670 boost::shared_ptr<Controllable> c;
3671 boost::shared_ptr<Stripable> s;
3672 boost::shared_ptr<Route> r;
3674 switch (desc.top_level_type()) {
3675 case ControllableDescriptor::NamedRoute:
3677 std::string str = desc.top_level_name();
3679 if (str == "Master" || str == "master") {
3681 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3683 } else if (str == "auditioner") {
3686 s = route_by_name (desc.top_level_name());
3692 case ControllableDescriptor::PresentationOrderRoute:
3693 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3696 case ControllableDescriptor::PresentationOrderTrack:
3697 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3700 case ControllableDescriptor::PresentationOrderBus:
3701 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3704 case ControllableDescriptor::PresentationOrderVCA:
3705 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3708 case ControllableDescriptor::SelectionCount:
3709 s = route_by_selected_count (desc.selection_id());
3717 r = boost::dynamic_pointer_cast<Route> (s);
3719 switch (desc.subtype()) {
3720 case ControllableDescriptor::Gain:
3721 c = s->gain_control ();
3724 case ControllableDescriptor::Trim:
3725 c = s->trim_control ();
3728 case ControllableDescriptor::Solo:
3729 c = s->solo_control();
3732 case ControllableDescriptor::Mute:
3733 c = s->mute_control();
3736 case ControllableDescriptor::Recenable:
3737 c = s->rec_enable_control ();
3740 case ControllableDescriptor::PanDirection:
3741 c = s->pan_azimuth_control();
3744 case ControllableDescriptor::PanWidth:
3745 c = s->pan_width_control();
3748 case ControllableDescriptor::PanElevation:
3749 c = s->pan_elevation_control();
3752 case ControllableDescriptor::Balance:
3753 /* XXX simple pan control */
3756 case ControllableDescriptor::PluginParameter:
3758 uint32_t plugin = desc.target (0);
3759 uint32_t parameter_index = desc.target (1);
3761 /* revert to zero based counting */
3767 if (parameter_index > 0) {
3775 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3778 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3779 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3784 case ControllableDescriptor::SendGain: {
3785 uint32_t send = desc.target (0);
3792 c = r->send_level_controllable (send);
3797 /* relax and return a null pointer */
3805 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3808 Stateful::add_instant_xml (node, _path);
3811 if (write_to_config) {
3812 Config->add_instant_xml (node);
3817 Session::instant_xml (const string& node_name)
3819 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3820 if (get_disable_all_loaded_plugins ()) {
3824 return Stateful::instant_xml (node_name, _path);
3828 Session::save_history (string snapshot_name)
3836 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3837 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3841 if (snapshot_name.empty()) {
3842 snapshot_name = _current_snapshot_name;
3845 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3846 const string backup_filename = history_filename + backup_suffix;
3847 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3848 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3850 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3851 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3852 error << _("could not backup old history file, current history not saved") << endmsg;
3857 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3859 if (!tree.write (xml_path))
3861 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3863 if (g_remove (xml_path.c_str()) != 0) {
3864 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3865 xml_path, g_strerror (errno)) << endmsg;
3867 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3868 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3869 backup_path, g_strerror (errno)) << endmsg;
3879 Session::restore_history (string snapshot_name)
3883 if (snapshot_name.empty()) {
3884 snapshot_name = _current_snapshot_name;
3887 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3888 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3890 info << "Loading history from " << xml_path << endmsg;
3892 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3893 info << string_compose (_("%1: no history file \"%2\" for this session."),
3894 _name, xml_path) << endmsg;
3898 if (!tree.read (xml_path)) {
3899 error << string_compose (_("Could not understand session history file \"%1\""),
3900 xml_path) << endmsg;
3907 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3910 UndoTransaction* ut = new UndoTransaction ();
3916 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3917 !t->get_property ("tv-usec", tv_usec)) {
3921 ut->set_name (name);
3925 tv.tv_usec = tv_usec;
3926 ut->set_timestamp(tv);
3928 for (XMLNodeConstIterator child_it = t->children().begin();
3929 child_it != t->children().end(); child_it++)
3931 XMLNode *n = *child_it;
3934 if (n->name() == "MementoCommand" ||
3935 n->name() == "MementoUndoCommand" ||
3936 n->name() == "MementoRedoCommand") {
3938 if ((c = memento_command_factory(n))) {
3942 } else if (n->name() == "NoteDiffCommand") {
3943 PBD::ID id (n->property("midi-source")->value());
3944 boost::shared_ptr<MidiSource> midi_source =
3945 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3947 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3949 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3952 } else if (n->name() == "SysExDiffCommand") {
3954 PBD::ID id (n->property("midi-source")->value());
3955 boost::shared_ptr<MidiSource> midi_source =
3956 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3958 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3960 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3963 } else if (n->name() == "PatchChangeDiffCommand") {
3965 PBD::ID id (n->property("midi-source")->value());
3966 boost::shared_ptr<MidiSource> midi_source =
3967 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3969 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3971 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3974 } else if (n->name() == "StatefulDiffCommand") {
3975 if ((c = stateful_diff_command_factory (n))) {
3976 ut->add_command (c);
3979 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3990 Session::config_changed (std::string p, bool ours)
3996 if (p == "seamless-loop") {
3998 } else if (p == "rf-speed") {
4000 } else if (p == "auto-loop") {
4002 } else if (p == "session-monitoring") {
4004 } else if (p == "auto-input") {
4006 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4007 /* auto-input only makes a difference if we're rolling */
4008 set_track_monitor_input_status (!config.get_auto_input());
4011 } else if (p == "punch-in") {
4015 if ((location = _locations->auto_punch_location()) != 0) {
4017 if (config.get_punch_in ()) {
4018 replace_event (SessionEvent::PunchIn, location->start());
4020 remove_event (location->start(), SessionEvent::PunchIn);
4024 } else if (p == "punch-out") {
4028 if ((location = _locations->auto_punch_location()) != 0) {
4030 if (config.get_punch_out()) {
4031 replace_event (SessionEvent::PunchOut, location->end());
4033 clear_events (SessionEvent::PunchOut);
4037 } else if (p == "edit-mode") {
4039 Glib::Threads::Mutex::Lock lm (playlists->lock);
4041 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4042 (*i)->set_edit_mode (Config->get_edit_mode ());
4045 } else if (p == "use-video-sync") {
4047 waiting_for_sync_offset = config.get_use_video_sync();
4049 } else if (p == "mmc-control") {
4051 //poke_midi_thread ();
4053 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4055 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4057 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4059 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4061 } else if (p == "midi-control") {
4063 //poke_midi_thread ();
4065 } else if (p == "raid-path") {
4067 setup_raid_path (config.get_raid_path());
4069 } else if (p == "timecode-format") {
4073 } else if (p == "video-pullup") {
4077 } else if (p == "seamless-loop") {
4079 if (play_loop && transport_rolling()) {
4080 // to reset diskstreams etc
4081 request_play_loop (true);
4084 } else if (p == "rf-speed") {
4086 cumulative_rf_motion = 0;
4089 } else if (p == "click-sound") {
4091 setup_click_sounds (1);
4093 } else if (p == "click-emphasis-sound") {
4095 setup_click_sounds (-1);
4097 } else if (p == "clicking") {
4099 if (Config->get_clicking()) {
4100 if (_click_io && click_data) { // don't require emphasis data
4107 } else if (p == "click-record-only") {
4109 _click_rec_only = Config->get_click_record_only();
4111 } else if (p == "click-gain") {
4114 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4117 } else if (p == "send-mtc") {
4119 if (Config->get_send_mtc ()) {
4120 /* mark us ready to send */
4121 next_quarter_frame_to_send = 0;
4124 } else if (p == "send-mmc") {
4126 _mmc->enable_send (Config->get_send_mmc ());
4128 } else if (p == "jack-time-master") {
4130 engine().reset_timebase ();
4132 } else if (p == "native-file-header-format") {
4134 if (!first_file_header_format_reset) {
4135 reset_native_file_format ();
4138 first_file_header_format_reset = false;
4140 } else if (p == "native-file-data-format") {
4142 if (!first_file_data_format_reset) {
4143 reset_native_file_format ();
4146 first_file_data_format_reset = false;
4148 } else if (p == "external-sync") {
4149 if (!config.get_external_sync()) {
4150 drop_sync_source ();
4152 switch_to_sync_source (Config->get_sync_source());
4154 } else if (p == "denormal-model") {
4156 } else if (p == "history-depth") {
4157 set_history_depth (Config->get_history_depth());
4158 } else if (p == "remote-model") {
4159 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4162 } else if (p == "initial-program-change") {
4164 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4167 buf[0] = MIDI::program; // channel zero by default
4168 buf[1] = (Config->get_initial_program_change() & 0x7f);
4170 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4172 } else if (p == "solo-mute-override") {
4173 // catch_up_on_solo_mute_override ();
4174 } else if (p == "listen-position" || p == "pfl-position") {
4175 listen_position_changed ();
4176 } else if (p == "solo-control-is-listen-control") {
4177 solo_control_mode_changed ();
4178 } else if (p == "solo-mute-gain") {
4179 _solo_cut_control->Changed (true, Controllable::NoGroup);
4180 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4181 last_timecode_valid = false;
4182 } else if (p == "playback-buffer-seconds") {
4183 AudioSource::allocate_working_buffers (frame_rate());
4184 } else if (p == "ltc-source-port") {
4185 reconnect_ltc_input ();
4186 } else if (p == "ltc-sink-port") {
4187 reconnect_ltc_output ();
4188 } else if (p == "timecode-generator-offset") {
4189 ltc_tx_parse_offset();
4190 } else if (p == "auto-return-target-list") {
4191 follow_playhead_priority ();
4198 Session::set_history_depth (uint32_t d)
4200 _history.set_depth (d);
4204 Session::load_diskstreams_2X (XMLNode const & node, int)
4207 XMLNodeConstIterator citer;
4209 clist = node.children();
4211 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4214 /* diskstreams added automatically by DiskstreamCreated handler */
4215 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4216 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4217 _diskstreams_2X.push_back (dsp);
4219 error << _("Session: unknown diskstream type in XML") << endmsg;
4223 catch (failed_constructor& err) {
4224 error << _("Session: could not load diskstream via XML state") << endmsg;
4232 /** Connect things to the MMC object */
4234 Session::setup_midi_machine_control ()
4236 _mmc = new MIDI::MachineControl;
4238 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4239 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4241 if (!async_out || !async_out) {
4245 /* XXXX argh, passing raw pointers back into libmidi++ */
4247 MIDI::Port* mmc_in = async_in.get();
4248 MIDI::Port* mmc_out = async_out.get();
4250 _mmc->set_ports (mmc_in, mmc_out);
4252 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4253 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4254 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4255 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4256 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4257 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4258 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4259 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4260 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4261 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4262 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4263 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4264 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4266 /* also handle MIDI SPP because its so common */
4268 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4269 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4270 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4273 boost::shared_ptr<Controllable>
4274 Session::solo_cut_control() const
4276 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4277 * controls in Ardour that currently get presented to the user in the GUI that require
4278 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4280 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4281 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4284 return _solo_cut_control;
4288 Session::save_snapshot_name (const std::string & n)
4290 /* assure Stateful::_instant_xml is loaded
4291 * add_instant_xml() only adds to existing data and defaults
4292 * to use an empty Tree otherwise
4294 instant_xml ("LastUsedSnapshot");
4296 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4297 last_used_snapshot->set_property ("name", n);
4298 add_instant_xml (*last_used_snapshot, false);
4302 Session::set_snapshot_name (const std::string & n)
4304 _current_snapshot_name = n;
4305 save_snapshot_name (n);
4309 Session::rename (const std::string& new_name)
4311 string legal_name = legalize_for_path (new_name);
4317 string const old_sources_root = _session_dir->sources_root();
4319 if (!_writable || (_state_of_the_state & CannotSave)) {
4320 error << _("Cannot rename read-only session.") << endmsg;
4321 return 0; // don't show "messed up" warning
4323 if (record_status() == Recording) {
4324 error << _("Cannot rename session while recording") << endmsg;
4325 return 0; // don't show "messed up" warning
4328 StateProtector stp (this);
4333 * interchange subdirectory
4337 * Backup files are left unchanged and not renamed.
4340 /* Windows requires that we close all files before attempting the
4341 * rename. This works on other platforms, but isn't necessary there.
4342 * Leave it in place for all platforms though, since it may help
4343 * catch issues that could arise if the way Source files work ever
4344 * change (since most developers are not using Windows).
4347 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4348 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4354 /* pass one: not 100% safe check that the new directory names don't
4358 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4362 /* this is a stupid hack because Glib::path_get_dirname() is
4363 * lexical-only, and so passing it /a/b/c/ gives a different
4364 * result than passing it /a/b/c ...
4367 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4368 oldstr = oldstr.substr (0, oldstr.length() - 1);
4371 string base = Glib::path_get_dirname (oldstr);
4373 newstr = Glib::build_filename (base, legal_name);
4375 cerr << "Looking for " << newstr << endl;
4377 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4378 cerr << " exists\n";
4387 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4393 /* this is a stupid hack because Glib::path_get_dirname() is
4394 * lexical-only, and so passing it /a/b/c/ gives a different
4395 * result than passing it /a/b/c ...
4398 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4399 oldstr = oldstr.substr (0, oldstr.length() - 1);
4402 string base = Glib::path_get_dirname (oldstr);
4403 newstr = Glib::build_filename (base, legal_name);
4405 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4407 cerr << "Rename " << oldstr << " => " << newstr << endl;
4408 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4409 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4410 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4414 /* Reset path in "session dirs" */
4419 /* reset primary SessionDirectory object */
4422 (*_session_dir) = newstr;
4427 /* now rename directory below session_dir/interchange */
4429 string old_interchange_dir;
4430 string new_interchange_dir;
4432 /* use newstr here because we renamed the path
4433 * (folder/directory) that used to be oldstr to newstr above
4436 v.push_back (newstr);
4437 v.push_back (interchange_dir_name);
4438 v.push_back (Glib::path_get_basename (oldstr));
4440 old_interchange_dir = Glib::build_filename (v);
4443 v.push_back (newstr);
4444 v.push_back (interchange_dir_name);
4445 v.push_back (legal_name);
4447 new_interchange_dir = Glib::build_filename (v);
4449 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4451 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4452 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4453 old_interchange_dir, new_interchange_dir,
4456 error << string_compose (_("renaming %s as %2 failed (%3)"),
4457 old_interchange_dir, new_interchange_dir,
4466 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4467 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4469 cerr << "Rename " << oldstr << " => " << newstr << endl;
4471 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4472 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4473 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4479 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4481 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4482 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4484 cerr << "Rename " << oldstr << " => " << newstr << endl;
4486 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4487 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4488 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4493 /* remove old name from recent sessions */
4494 remove_recent_sessions (_path);
4497 /* update file source paths */
4499 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4500 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4502 string p = fs->path ();
4503 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4505 SourceFactory::setup_peakfile(i->second, true);
4509 set_snapshot_name (new_name);
4514 /* save state again to get everything just right */
4516 save_state (_current_snapshot_name);
4518 /* add to recent sessions */
4520 store_recent_sessions (new_name, _path);
4526 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4528 bool found_sr = false;
4529 bool found_data_format = false;
4530 program_version = "";
4532 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4536 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4540 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4543 xmlFreeParserCtxt(ctxt);
4547 xmlNodePtr node = xmlDocGetRootElement(doc);
4550 xmlFreeParserCtxt(ctxt);
4558 for (attr = node->properties; attr; attr = attr->next) {
4559 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4560 sample_rate = atoi ((char*)attr->children->content);
4565 node = node->children;
4566 while (node != NULL) {
4567 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4568 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4570 program_version = string ((const char*)val);
4571 size_t sep = program_version.find_first_of("-");
4572 if (sep != string::npos) {
4573 program_version = program_version.substr (0, sep);
4578 if (strcmp((const char*) node->name, "Config")) {
4582 for (node = node->children; node; node = node->next) {
4583 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4584 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4586 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4588 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4590 found_data_format = true;
4600 xmlFreeParserCtxt(ctxt);
4603 return !(found_sr && found_data_format); // zero if they are both found
4607 Session::get_snapshot_from_instant (const std::string& session_dir)
4609 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4611 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4616 if (!tree.read (instant_xml_path)) {
4620 XMLProperty const * prop;
4621 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4622 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4623 return prop->value();
4629 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4630 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4633 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4637 SourcePathMap source_path_map;
4639 boost::shared_ptr<AudioFileSource> afs;
4644 Glib::Threads::Mutex::Lock lm (source_lock);
4646 cerr << " total sources = " << sources.size();
4648 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4649 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4655 if (fs->within_session()) {
4659 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4660 source_path_map[fs->path()].push_back (fs);
4662 SeveralFileSources v;
4664 source_path_map.insert (make_pair (fs->path(), v));
4670 cerr << " fsources = " << total << endl;
4672 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4674 /* tell caller where we are */
4676 string old_path = i->first;
4678 callback (n, total, old_path);
4680 cerr << old_path << endl;
4684 switch (i->second.front()->type()) {
4685 case DataType::AUDIO:
4686 new_path = new_audio_source_path_for_embedded (old_path);
4689 case DataType::MIDI:
4690 /* XXX not implemented yet */
4694 if (new_path.empty()) {
4698 cerr << "Move " << old_path << " => " << new_path << endl;
4700 if (!copy_file (old_path, new_path)) {
4701 cerr << "failed !\n";
4705 /* make sure we stop looking in the external
4706 dir/folder. Remember, this is an all-or-nothing
4707 operations, it doesn't merge just some files.
4709 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4711 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4712 (*f)->set_path (new_path);
4717 save_state ("", false, false);
4723 bool accept_all_files (string const &, void *)
4729 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4731 /* 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.
4736 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4738 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4740 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4742 v.push_back (new_session_folder); /* full path */
4743 v.push_back (interchange_dir_name);
4744 v.push_back (new_session_path); /* just one directory/folder */
4745 v.push_back (typedir);
4746 v.push_back (Glib::path_get_basename (old_path));
4748 return Glib::build_filename (v);
4752 Session::save_as (SaveAs& saveas)
4754 vector<string> files;
4755 string current_folder = Glib::path_get_dirname (_path);
4756 string new_folder = legalize_for_path (saveas.new_name);
4757 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4758 int64_t total_bytes = 0;
4762 int32_t internal_file_cnt = 0;
4764 vector<string> do_not_copy_extensions;
4765 do_not_copy_extensions.push_back (statefile_suffix);
4766 do_not_copy_extensions.push_back (pending_suffix);
4767 do_not_copy_extensions.push_back (backup_suffix);
4768 do_not_copy_extensions.push_back (temp_suffix);
4769 do_not_copy_extensions.push_back (history_suffix);
4771 /* get total size */
4773 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4775 /* need to clear this because
4776 * find_files_matching_filter() is cumulative
4781 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4783 all += files.size();
4785 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4787 g_stat ((*i).c_str(), &gsb);
4788 total_bytes += gsb.st_size;
4792 /* save old values so we can switch back if we are not switching to the new session */
4794 string old_path = _path;
4795 string old_name = _name;
4796 string old_snapshot = _current_snapshot_name;
4797 string old_sd = _session_dir->root_path();
4798 vector<string> old_search_path[DataType::num_types];
4799 string old_config_search_path[DataType::num_types];
4801 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4802 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4803 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4804 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4806 /* switch session directory */
4808 (*_session_dir) = to_dir;
4810 /* create new tree */
4812 if (!_session_dir->create()) {
4813 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4818 /* copy all relevant files. Find each location in session_dirs,
4819 * and copy files from there to target.
4822 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4824 /* need to clear this because
4825 * find_files_matching_filter() is cumulative
4830 const size_t prefix_len = (*sd).path.size();
4832 /* Work just on the files within this session dir */
4834 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4836 /* add dir separator to protect against collisions with
4837 * track names (e.g. track named "audiofiles" or
4841 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4842 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4843 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4845 /* copy all the files. Handling is different for media files
4846 than others because of the *silly* subtree we have below the interchange
4847 folder. That really was a bad idea, but I'm not fixing it as part of
4848 implementing ::save_as().
4851 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4853 std::string from = *i;
4856 string filename = Glib::path_get_basename (from);
4857 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4858 if (filename == ".DS_STORE") {
4863 if (from.find (audiofile_dir_string) != string::npos) {
4865 /* audio file: only copy if asked */
4867 if (saveas.include_media && saveas.copy_media) {
4869 string to = make_new_media_path (*i, to_dir, new_folder);
4871 info << "media file copying from " << from << " to " << to << endmsg;
4873 if (!copy_file (from, to)) {
4874 throw Glib::FileError (Glib::FileError::IO_ERROR,
4875 string_compose(_("\ncopying \"%1\" failed !"), from));
4879 /* we found media files inside the session folder */
4881 internal_file_cnt++;
4883 } else if (from.find (midifile_dir_string) != string::npos) {
4885 /* midi file: always copy unless
4886 * creating an empty new session
4889 if (saveas.include_media) {
4891 string to = make_new_media_path (*i, to_dir, new_folder);
4893 info << "media file copying from " << from << " to " << to << endmsg;
4895 if (!copy_file (from, to)) {
4896 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4900 /* we found media files inside the session folder */
4902 internal_file_cnt++;
4904 } else if (from.find (analysis_dir_string) != string::npos) {
4906 /* make sure analysis dir exists in
4907 * new session folder, but we're not
4908 * copying analysis files here, see
4912 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4917 /* normal non-media file. Don't copy state, history, etc.
4920 bool do_copy = true;
4922 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4923 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4924 /* end of filename matches extension, do not copy file */
4930 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4931 /* don't copy peakfiles if
4932 * we're not copying media
4938 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4940 info << "attempting to make directory/folder " << to << endmsg;
4942 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4943 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4946 info << "attempting to copy " << from << " to " << to << endmsg;
4948 if (!copy_file (from, to)) {
4949 throw Glib::FileError (Glib::FileError::IO_ERROR,
4950 string_compose(_("\ncopying \"%1\" failed !"), from));
4955 /* measure file size even if we're not going to copy so that our Progress
4956 signals are correct, since we included these do-not-copy files
4957 in the computation of the total size and file count.
4961 g_stat (from.c_str(), &gsb);
4962 copied += gsb.st_size;
4965 double fraction = (double) copied / total_bytes;
4967 bool keep_going = true;
4969 if (saveas.copy_media) {
4971 /* no need or expectation of this if
4972 * media is not being copied, because
4973 * it will be fast(ish).
4976 /* tell someone "X percent, file M of N"; M is one-based */
4978 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4986 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4992 /* copy optional folders, if any */
4994 string old = plugins_dir ();
4995 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4996 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4997 copy_files (old, newdir);
5000 old = externals_dir ();
5001 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5002 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5003 copy_files (old, newdir);
5006 old = automation_dir ();
5007 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5008 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5009 copy_files (old, newdir);
5012 if (saveas.include_media) {
5014 if (saveas.copy_media) {
5015 #ifndef PLATFORM_WINDOWS
5016 /* There are problems with analysis files on
5017 * Windows, because they used a colon in their
5018 * names as late as 4.0. Colons are not legal
5019 * under Windows even if NTFS allows them.
5021 * This is a tricky problem to solve so for
5022 * just don't copy these files. They will be
5023 * regenerated as-needed anyway, subject to the
5024 * existing issue that the filenames will be
5025 * rejected by Windows, which is a separate
5026 * problem (though related).
5029 /* only needed if we are copying media, since the
5030 * analysis data refers to media data
5033 old = analysis_dir ();
5034 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5035 string newdir = Glib::build_filename (to_dir, "analysis");
5036 copy_files (old, newdir);
5038 #endif /* PLATFORM_WINDOWS */
5043 set_snapshot_name (saveas.new_name);
5044 _name = saveas.new_name;
5046 if (saveas.include_media && !saveas.copy_media) {
5048 /* reset search paths of the new session (which we're pretending to be right now) to
5049 include the original session search path, so we can still find all audio.
5052 if (internal_file_cnt) {
5053 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5054 ensure_search_path_includes (*s, DataType::AUDIO);
5055 cerr << "be sure to include " << *s << " for audio" << endl;
5058 /* we do not do this for MIDI because we copy
5059 all MIDI files if saveas.include_media is
5065 bool was_dirty = dirty ();
5067 save_default_options ();
5069 if (saveas.copy_media && saveas.copy_external) {
5070 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5071 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5075 saveas.final_session_folder_name = _path;
5077 store_recent_sessions (_name, _path);
5079 if (!saveas.switch_to) {
5081 /* save the new state */
5083 save_state ("", false, false, !saveas.include_media);
5085 /* switch back to the way things were */
5089 set_snapshot_name (old_snapshot);
5091 (*_session_dir) = old_sd;
5097 if (internal_file_cnt) {
5098 /* reset these to their original values */
5099 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5100 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5105 /* prune session dirs, and update disk space statistics
5110 session_dirs.clear ();
5111 session_dirs.push_back (sp);
5112 refresh_disk_space ();
5114 _writable = exists_and_writable (_path);
5116 /* ensure that all existing tracks reset their current capture source paths
5118 reset_write_sources (true, true);
5120 /* creating new write sources marks the session as
5121 dirty. If the new session is empty, then
5122 save_state() thinks we're saving a template and will
5123 not mark the session as clean. So do that here,
5124 before we save state.
5127 if (!saveas.include_media) {
5128 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5131 save_state ("", false, false, !saveas.include_media);
5133 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5134 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5137 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5138 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5144 if (fs->within_session()) {
5145 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5146 fs->set_path (newpath);
5151 } catch (Glib::FileError& e) {
5153 saveas.failure_message = e.what();
5155 /* recursively remove all the directories */
5157 remove_directory (to_dir);
5165 saveas.failure_message = _("unknown reason");
5167 /* recursively remove all the directories */
5169 remove_directory (to_dir);
5179 static void set_progress (Progress* p, size_t n, size_t t)
5181 p->set_progress (float (n) / float(t));
5185 Session::archive_session (const std::string& dest,
5186 const std::string& name,
5187 ArchiveEncode compress_audio,
5188 bool only_used_sources,
5191 if (dest.empty () || name.empty ()) {
5195 /* save current values */
5196 bool was_dirty = dirty ();
5197 string old_path = _path;
5198 string old_name = _name;
5199 string old_snapshot = _current_snapshot_name;
5200 string old_sd = _session_dir->root_path();
5201 string old_config_search_path[DataType::num_types];
5202 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5203 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5205 /* ensure that session-path is included in search-path */
5207 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5208 if ((*sd).path == old_path) {
5216 /* create temporary dir to save session to */
5217 #ifdef PLATFORM_WINDOWS
5218 char tmp[256] = "C:\\TEMP\\";
5219 GetTempPath (sizeof (tmp), tmp);
5221 char const* tmp = getenv("TMPDIR");
5226 if ((strlen (tmp) + 21) > 1024) {
5231 strcpy (tmptpl, tmp);
5232 strcat (tmptpl, "ardourarchive-XXXXXX");
5233 char* tmpdir = g_mkdtemp (tmptpl);
5239 std::string to_dir = std::string (tmpdir);
5241 /* switch session directory temporarily */
5242 (*_session_dir) = to_dir;
5244 if (!_session_dir->create()) {
5245 (*_session_dir) = old_sd;
5246 remove_directory (to_dir);
5250 /* prepare archive */
5251 string archive = Glib::build_filename (dest, name + ".tar.xz");
5253 PBD::ScopedConnectionList progress_connection;
5254 PBD::FileArchive ar (archive);
5256 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5259 /* collect files to archive */
5260 std::map<string,string> filemap;
5262 vector<string> do_not_copy_extensions;
5263 do_not_copy_extensions.push_back (statefile_suffix);
5264 do_not_copy_extensions.push_back (pending_suffix);
5265 do_not_copy_extensions.push_back (backup_suffix);
5266 do_not_copy_extensions.push_back (temp_suffix);
5267 do_not_copy_extensions.push_back (history_suffix);
5269 vector<string> blacklist_dirs;
5270 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5271 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5272 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5273 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5274 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5275 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5277 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5278 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5280 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5281 if (only_used_sources) {
5282 playlists->sync_all_regions_with_regions ();
5283 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5286 // collect audio sources for this session, calc total size for encoding
5287 // add option to only include *used* sources (see Session::cleanup_sources)
5288 size_t total_size = 0;
5290 Glib::Threads::Mutex::Lock lm (source_lock);
5291 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5292 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5293 if (!afs || afs->readable_length () == 0) {
5297 if (only_used_sources) {
5301 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5306 std::string from = afs->path();
5308 if (compress_audio != NO_ENCODE) {
5309 total_size += afs->readable_length ();
5311 if (afs->within_session()) {
5312 filemap[from] = make_new_media_path (from, name, name);
5314 filemap[from] = make_new_media_path (from, name, name);
5315 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5322 if (compress_audio != NO_ENCODE) {
5324 progress->set_progress (2); // set to "encoding"
5325 progress->set_progress (0);
5328 Glib::Threads::Mutex::Lock lm (source_lock);
5329 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5330 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5331 if (!afs || afs->readable_length () == 0) {
5335 if (only_used_sources) {
5339 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5344 orig_sources[afs] = afs->path();
5345 orig_gain[afs] = afs->gain();
5347 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5348 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5349 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5352 progress->descend ((float)afs->readable_length () / total_size);
5356 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5357 afs->replace_file (new_path);
5358 afs->set_gain (ns->gain(), true);
5361 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5365 progress->ascend ();
5371 progress->set_progress (-1); // set to "archiving"
5372 progress->set_progress (0);
5375 /* index files relevant for this session */
5376 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5377 vector<string> files;
5379 size_t prefix_len = (*sd).path.size();
5380 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5384 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5386 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5387 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5388 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5390 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5391 std::string from = *i;
5394 string filename = Glib::path_get_basename (from);
5395 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5396 if (filename == ".DS_STORE") {
5401 if (from.find (audiofile_dir_string) != string::npos) {
5403 } else if (from.find (midifile_dir_string) != string::npos) {
5404 filemap[from] = make_new_media_path (from, name, name);
5405 } else if (from.find (videofile_dir_string) != string::npos) {
5406 filemap[from] = make_new_media_path (from, name, name);
5408 bool do_copy = true;
5409 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5410 if (from.find (*v) != string::npos) {
5415 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5416 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5423 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5429 /* write session file */
5431 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5433 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5436 save_default_options ();
5438 size_t prefix_len = _path.size();
5439 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5443 /* collect session-state files */
5444 vector<string> files;
5445 do_not_copy_extensions.clear ();
5446 do_not_copy_extensions.push_back (history_suffix);
5448 blacklist_dirs.clear ();
5449 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5451 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5452 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5453 std::string from = *i;
5454 bool do_copy = true;
5455 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5456 if (from.find (*v) != string::npos) {
5461 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5462 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5468 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5472 /* restore original values */
5475 set_snapshot_name (old_snapshot);
5476 (*_session_dir) = old_sd;
5480 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5481 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5483 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5484 i->first->replace_file (i->second);
5486 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5487 i->first->set_gain (i->second, true);
5490 int rv = ar.create (filemap);
5491 remove_directory (to_dir);
5497 Session::undo (uint32_t n)
5499 if (actively_recording()) {
5507 Session::redo (uint32_t n)
5509 if (actively_recording()) {