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_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/auditioner.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/boost_debug.h"
87 #include "ardour/butler.h"
88 #include "ardour/controllable_descriptor.h"
89 #include "ardour/control_protocol_manager.h"
90 #include "ardour/directory_names.h"
91 #include "ardour/disk_reader.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/selection.h"
118 #include "ardour/session.h"
119 #include "ardour/session_directory.h"
120 #include "ardour/session_metadata.h"
121 #include "ardour/session_playlists.h"
122 #include "ardour/session_state_utils.h"
123 #include "ardour/silentfilesource.h"
124 #include "ardour/smf_source.h"
125 #include "ardour/sndfilesource.h"
126 #include "ardour/source_factory.h"
127 #include "ardour/speakers.h"
128 #include "ardour/template_utils.h"
129 #include "ardour/tempo.h"
130 #include "ardour/ticker.h"
131 #include "ardour/types_convert.h"
132 #include "ardour/user_bundle.h"
133 #include "ardour/vca.h"
134 #include "ardour/vca_manager.h"
136 #include "control_protocol/control_protocol.h"
138 #include "LuaBridge/LuaBridge.h"
140 #include "pbd/i18n.h"
144 using namespace ARDOUR;
147 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
150 Session::pre_engine_init (string fullpath)
152 if (fullpath.empty()) {
154 throw failed_constructor();
157 /* discover canonical fullpath */
159 _path = canonical_path(fullpath);
162 if (Profile->get_trx() ) {
163 // Waves TracksLive has a usecase of session replacement with a new one.
164 // We should check session state file (<session_name>.ardour) existance
165 // to determine if the session is new or not
167 string full_session_name = Glib::build_filename( fullpath, _name );
168 full_session_name += statefile_suffix;
170 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
186 interpolation.add_channel ();
188 if (config.get_use_video_sync()) {
189 waiting_for_sync_offset = true;
191 waiting_for_sync_offset = false;
194 last_rr_session_dir = session_dirs.begin();
196 set_history_depth (Config->get_history_depth());
198 /* default: assume simple stereo speaker configuration */
200 _speakers->setup_default_speakers (2);
202 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
203 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
204 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
205 add_controllable (_solo_cut_control);
207 /* These are all static "per-class" signals */
209 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
210 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
211 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
212 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
213 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
215 /* stop IO objects from doing stuff until we're ready for them */
217 Delivery::disable_panners ();
218 IO::disable_connecting ();
222 Session::post_engine_init ()
224 BootMessage (_("Set block size and sample rate"));
226 set_block_size (_engine.samples_per_cycle());
227 set_sample_rate (_engine.sample_rate());
229 BootMessage (_("Using configuration"));
231 _midi_ports = new MidiPortManager;
233 MIDISceneChanger* msc;
235 _scene_changer = msc = new MIDISceneChanger (*this);
236 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
237 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
239 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
240 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
242 setup_midi_machine_control ();
244 if (_butler->start_thread()) {
245 error << _("Butler did not start") << endmsg;
249 if (start_midi_thread ()) {
250 error << _("MIDI I/O thread did not start") << endmsg;
254 setup_click_sounds (0);
255 setup_midi_control ();
257 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
258 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
261 /* tempo map requires sample rate knowledge */
264 _tempo_map = new TempoMap (_current_sample_rate);
265 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 } catch (std::exception const & e) {
268 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
271 error << _("Unknown exception during session setup") << endmsg;
276 /* MidiClock requires a tempo map */
279 midi_clock = new MidiClockTicker ();
280 midi_clock->set_session (this);
282 /* crossfades require sample rate knowledge */
284 SndFileSource::setup_standard_crossfades (*this, sample_rate());
285 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
286 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
288 DiskReader::allocate_working_buffers();
289 refresh_disk_space ();
291 /* we're finally ready to call set_state() ... all objects have
292 * been created, the engine is running.
297 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
298 error << _("Could not set session state from XML") << endmsg;
301 } catch (PBD::unknown_enumeration& e) {
302 error << _("Session state: ") << e.what() << endmsg;
306 // set_state() will call setup_raid_path(), but if it's a new session we need
307 // to call setup_raid_path() here.
308 setup_raid_path (_path);
313 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
314 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
316 Config->map_parameters (ff);
317 config.map_parameters (ft);
318 _butler->map_parameters ();
320 /* Reset all panners */
322 Delivery::reset_panners ();
324 /* this will cause the CPM to instantiate any protocols that are in use
325 * (or mandatory), which will pass it this Session, and then call
326 * set_state() on each instantiated protocol to match stored state.
329 ControlProtocolManager::instance().set_session (this);
331 /* This must be done after the ControlProtocolManager set_session above,
332 as it will set states for ports which the ControlProtocolManager creates.
335 // XXX set state of MIDI::Port's
336 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
338 /* And this must be done after the MIDI::Manager::set_port_states as
339 * it will try to make connections whose details are loaded by set_port_states.
344 /* Let control protocols know that we are now all connected, so they
345 * could start talking to surfaces if they want to.
348 ControlProtocolManager::instance().midi_connectivity_established ();
350 if (_is_new && !no_auto_connect()) {
351 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
352 auto_connect_master_bus ();
355 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
357 /* update latencies */
359 initialize_latencies ();
361 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
362 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
363 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
365 } catch (AudioEngine::PortRegistrationFailure& err) {
366 error << err.what() << endmsg;
368 } catch (std::exception const & e) {
369 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
372 error << _("Unknown exception during session setup") << endmsg;
376 BootMessage (_("Reset Remote Controls"));
378 // send_full_time_code (0);
379 _engine.transport_locate (0);
381 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
382 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
384 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
387 /* initial program change will be delivered later; see ::config_changed() */
389 _state_of_the_state = Clean;
391 Port::set_connecting_blocked (false);
393 DirtyChanged (); /* EMIT SIGNAL */
397 } else if (state_was_pending) {
399 remove_pending_capture_state ();
400 state_was_pending = false;
403 /* Now, finally, we can fill the playback buffers */
405 BootMessage (_("Filling playback buffers"));
407 boost::shared_ptr<RouteList> rl = routes.reader();
408 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
409 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
410 if (trk && !trk->is_private_route()) {
411 trk->seek (_transport_sample, true);
419 Session::session_loaded ()
423 _state_of_the_state = Clean;
425 DirtyChanged (); /* EMIT SIGNAL */
429 } else if (state_was_pending) {
431 remove_pending_capture_state ();
432 state_was_pending = false;
435 /* Now, finally, we can fill the playback buffers */
437 BootMessage (_("Filling playback buffers"));
438 force_locate (_transport_sample, false);
442 Session::raid_path () const
444 Searchpath raid_search_path;
446 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
447 raid_search_path += (*i).path;
450 return raid_search_path.to_string ();
454 Session::setup_raid_path (string path)
463 session_dirs.clear ();
465 Searchpath search_path(path);
466 Searchpath sound_search_path;
467 Searchpath midi_search_path;
469 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
471 sp.blocks = 0; // not needed
472 session_dirs.push_back (sp);
474 SessionDirectory sdir(sp.path);
476 sound_search_path += sdir.sound_path ();
477 midi_search_path += sdir.midi_path ();
480 // reset the round-robin soundfile path thingie
481 last_rr_session_dir = session_dirs.begin();
485 Session::path_is_within_session (const std::string& path)
487 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
488 if (PBD::path_is_within (i->path, path)) {
496 Session::ensure_subdirs ()
500 dir = session_directory().peak_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = session_directory().sound_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().midi_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = session_directory().dead_path();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = session_directory().export_path();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 dir = analysis_dir ();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
542 dir = plugins_dir ();
544 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
545 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
549 dir = externals_dir ();
551 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
559 /** @param session_template directory containing session template, or empty.
560 * Caller must not hold process lock.
563 Session::create (const string& session_template, BusProfile* bus_profile)
565 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
566 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
570 if (ensure_subdirs ()) {
574 _writable = exists_and_writable (_path);
576 if (!session_template.empty()) {
577 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
579 FILE* in = g_fopen (in_path.c_str(), "rb");
582 /* no need to call legalize_for_path() since the string
583 * in session_template is already a legal path name
585 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
587 FILE* out = g_fopen (out_path.c_str(), "wb");
591 stringstream new_session;
594 size_t charsRead = fread (buf, sizeof(char), 1024, in);
597 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
602 if (charsRead == 0) {
605 new_session.write (buf, charsRead);
609 string file_contents = new_session.str();
610 size_t writeSize = file_contents.length();
611 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
612 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
620 if (!ARDOUR::Profile->get_trx()) {
621 /* Copy plugin state files from template to new session */
622 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
623 copy_recurse (template_plugins, plugins_dir ());
629 error << string_compose (_("Could not open %1 for writing session template"), out_path)
636 error << string_compose (_("Could not open session template %1 for reading"), in_path)
643 if (Profile->get_trx()) {
645 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
646 * Remember that this is a brand new session. Sessions
647 * loaded from saved state will get this range from the saved state.
650 set_session_range_location (0, 0);
652 /* Initial loop location, from absolute zero, length 10 seconds */
654 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
655 _locations->add (loc, true);
656 set_auto_loop_location (loc);
659 _state_of_the_state = Clean;
661 /* set up Master Out and Monitor Out if necessary */
665 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
666 if (bus_profile->master_out_channels) {
667 int rv = add_master_bus (count);
673 if (Config->get_use_monitor_bus())
674 add_monitor_section ();
682 Session::maybe_write_autosave()
684 if (dirty() && record_status() != Recording) {
685 save_state("", true);
690 Session::remove_pending_capture_state ()
692 std::string pending_state_file_path(_session_dir->root_path());
694 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
698 if (g_remove (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 /** Rename a state file.
705 * @param old_name Old snapshot name.
706 * @param new_name New snapshot name.
709 Session::rename_state (string old_name, string new_name)
711 if (old_name == _current_snapshot_name || old_name == _name) {
712 /* refuse to rename the current snapshot or the "main" one */
716 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
717 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
719 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
720 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
722 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
723 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
724 old_name, new_name, g_strerror(errno)) << endmsg;
728 /** Remove a state file.
729 * @param snapshot_name Snapshot name.
732 Session::remove_state (string snapshot_name)
734 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
735 // refuse to remove the current snapshot or the "main" one
739 std::string xml_path(_session_dir->root_path());
741 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
743 if (!create_backup_file (xml_path)) {
744 // don't remove it if a backup can't be made
745 // create_backup_file will log the error.
750 if (g_remove (xml_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
752 xml_path, g_strerror (errno)) << endmsg;
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
760 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
763 std::string xml_path(_session_dir->root_path());
765 /* prevent concurrent saves from different threads */
767 Glib::Threads::Mutex::Lock lm (save_state_lock);
769 if (!_writable || (_state_of_the_state & CannotSave)) {
773 if (g_atomic_int_get(&_suspend_save)) {
777 _save_queued = false;
779 snapshot_t fork_state = NormalSave;
780 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
781 /* snapshot, close midi */
782 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
786 const int64_t save_start_time = g_get_monotonic_time();
789 /* tell sources we're saving first, in case they write out to a new file
790 * which should be saved with the state rather than the old one */
791 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
793 i->second->session_saved();
794 } catch (Evoral::SMF::FileError& e) {
795 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
799 SessionSaveUnderway (); /* EMIT SIGNAL */
801 bool mark_as_clean = true;
803 if (!snapshot_name.empty() && !switch_to_snapshot) {
804 mark_as_clean = false;
808 mark_as_clean = false;
809 tree.set_root (&get_template());
811 tree.set_root (&state (true, fork_state));
814 if (snapshot_name.empty()) {
815 snapshot_name = _current_snapshot_name;
816 } else if (switch_to_snapshot) {
817 set_snapshot_name (snapshot_name);
820 assert (!snapshot_name.empty());
824 /* proper save: use statefile_suffix (.ardour in English) */
826 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
828 /* make a backup copy of the old file */
830 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
831 // create_backup_file will log the error
837 /* pending save: use pending_suffix (.pending in English) */
838 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
841 std::string tmp_path(_session_dir->root_path());
842 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
845 cerr << "actually writing state to " << tmp_path << endl;
848 if (!tree.write (tmp_path)) {
849 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
850 if (g_remove (tmp_path.c_str()) != 0) {
851 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
852 tmp_path, g_strerror (errno)) << endmsg;
859 cerr << "renaming state to " << xml_path << endl;
862 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
863 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
864 tmp_path, xml_path, g_strerror(errno)) << endmsg;
865 if (g_remove (tmp_path.c_str()) != 0) {
866 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
867 tmp_path, g_strerror (errno)) << endmsg;
875 save_history (snapshot_name);
878 bool was_dirty = dirty();
880 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
883 DirtyChanged (); /* EMIT SIGNAL */
887 StateSaved (snapshot_name); /* EMIT SIGNAL */
891 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
892 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
898 Session::restore_state (string snapshot_name)
901 if (load_state (snapshot_name) == 0) {
902 set_state (*state_tree->root(), Stateful::loading_state_version);
906 // unknown_enumeration
914 Session::load_state (string snapshot_name)
919 state_was_pending = false;
921 /* check for leftover pending state from a crashed capture attempt */
923 std::string xmlpath(_session_dir->root_path());
924 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
926 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
928 /* there is pending state from a crashed capture attempt */
930 boost::optional<int> r = AskAboutPendingState();
931 if (r.get_value_or (1)) {
932 state_was_pending = true;
936 if (!state_was_pending) {
937 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
940 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
941 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
942 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
943 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
948 state_tree = new XMLTree;
952 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
954 if (!state_tree->read (xmlpath)) {
955 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
961 XMLNode const & root (*state_tree->root());
963 if (root.name() != X_("Session")) {
964 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
971 root.get_property ("version", version);
972 Stateful::loading_state_version = parse_stateful_loading_version (version);
974 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
975 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
976 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
979 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
981 std::string backup_path(_session_dir->root_path());
982 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
983 backup_path = Glib::build_filename (backup_path, backup_filename);
985 // only create a backup for a given statefile version once
987 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
989 VersionMismatch (xmlpath, backup_path);
991 if (!copy_file (xmlpath, backup_path)) {;
997 save_snapshot_name (snapshot_name);
1003 Session::load_options (const XMLNode& node)
1005 config.set_variables (node);
1010 Session::save_default_options ()
1012 return config.save_state();
1016 Session::get_state()
1022 Session::get_template()
1024 /* if we don't disable rec-enable, diskstreams
1025 will believe they need to store their capture
1026 sources in their state node.
1029 disable_record (false);
1031 return state(false);
1034 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1035 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1038 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1040 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1043 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1047 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1050 XMLNode* node = new XMLNode("TrackState"); // XXX
1053 PlaylistSet playlists; // SessionPlaylists
1056 // these will work with new_route_from_template()
1057 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1058 child = node->add_child ("Routes");
1059 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1060 if ((*i)->is_auditioner()) {
1063 if ((*i)->is_master() || (*i)->is_monitor()) {
1066 child->add_child_nocopy ((*i)->get_state());
1067 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1069 playlists.insert (track->playlist ());
1073 // on load, Regions in the playlists need to resolve and map Source-IDs
1074 // also playlist needs to be merged or created with new-name..
1075 // ... and Diskstream in tracks adjusted to use the correct playlist
1076 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1077 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1078 child->add_child_nocopy ((*i)->get_state ());
1079 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1080 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1081 const Region::SourceList& sl = (*s)->sources ();
1082 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1083 sources.insert (*sli);
1088 child = node->add_child ("Sources");
1089 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1090 child->add_child_nocopy ((*i)->get_state ());
1091 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1093 #ifdef PLATFORM_WINDOWS
1096 string p = fs->path ();
1097 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1101 std::string sn = Glib::build_filename (path, "share.axml");
1104 tree.set_root (node);
1105 return tree.write (sn.c_str());
1110 struct route_id_compare {
1112 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1114 return r1->id () < r2->id ();
1120 Session::state (bool full_state, snapshot_t snapshot_type)
1123 XMLNode* node = new XMLNode("Session");
1126 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1128 child = node->add_child ("ProgramVersion");
1129 child->set_property("created-with", created_with);
1131 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1132 child->set_property("modified-with", modified_with);
1134 /* store configuration settings */
1138 node->set_property ("name", _name);
1139 node->set_property ("sample-rate", _base_sample_rate);
1141 if (session_dirs.size() > 1) {
1145 vector<space_and_path>::iterator i = session_dirs.begin();
1146 vector<space_and_path>::iterator next;
1148 ++i; /* skip the first one */
1152 while (i != session_dirs.end()) {
1156 if (next != session_dirs.end()) {
1157 p += G_SEARCHPATH_SEPARATOR;
1166 child = node->add_child ("Path");
1167 child->add_content (p);
1169 node->set_property ("end-is-free", _session_range_end_is_free);
1172 /* save the ID counter */
1174 node->set_property ("id-counter", ID::counter());
1176 node->set_property ("name-counter", name_id_counter ());
1178 /* save the event ID counter */
1180 node->set_property ("event-counter", Evoral::event_id_counter());
1182 /* save the VCA counter */
1184 node->set_property ("vca-counter", VCA::get_next_vca_number());
1186 /* various options */
1188 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1189 if (!midi_port_nodes.empty()) {
1190 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1191 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1192 midi_port_stuff->add_child_nocopy (**n);
1194 node->add_child_nocopy (*midi_port_stuff);
1197 XMLNode& cfgxml (config.get_variables ());
1199 /* exclude search-paths from template */
1200 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1201 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1202 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1204 node->add_child_nocopy (cfgxml);
1206 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1208 child = node->add_child ("Sources");
1211 Glib::Threads::Mutex::Lock sl (source_lock);
1213 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1215 /* Don't save information about non-file Sources, or
1216 * about non-destructive file sources that are empty
1217 * and unused by any regions.
1219 boost::shared_ptr<FileSource> fs;
1221 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1225 if (!fs->destructive()) {
1226 if (fs->empty() && !fs->used()) {
1231 if (snapshot_type != NormalSave && fs->within_session ()) {
1232 /* copy MIDI sources to new file
1234 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1235 * because the GUI (midi_region) has a direct pointer to the midi-model
1236 * of the source, as does UndoTransaction.
1238 * On the upside, .mid files are not kept open. The file is only open
1239 * when reading the model initially and when flushing the model to disk:
1240 * source->session_saved () or export.
1242 * We can change the _path of the existing source under the hood, keeping
1243 * all IDs, references and pointers intact.
1245 boost::shared_ptr<SMFSource> ms;
1246 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1247 const std::string ancestor_name = ms->ancestor_name();
1248 const std::string base = PBD::basename_nosuffix(ancestor_name);
1249 const string path = new_midi_source_path (base, false);
1251 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1252 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1253 Source::Lock lm (ms->mutex());
1255 // TODO special-case empty, removable() files: just create a new removable.
1256 // (load + write flushes the model and creates the file)
1258 ms->load_model (lm);
1260 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1261 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1263 if (snapshot_type == SnapshotKeep) {
1264 /* keep working on current session.
1266 * Save snapshot-state with the original filename.
1267 * Switch to use new path for future saves of the main session.
1269 child->add_child_nocopy (ms->get_state());
1273 * ~SMFSource unlinks removable() files.
1275 std::string npath (ms->path ());
1276 ms->replace_file (newsrc->path ());
1277 newsrc->replace_file (npath);
1279 if (snapshot_type == SwitchToSnapshot) {
1280 /* save and switch to snapshot.
1282 * Leave the old file in place (as is).
1283 * Snapshot uses new source directly
1285 child->add_child_nocopy (ms->get_state());
1292 child->add_child_nocopy (siter->second->get_state());
1296 child = node->add_child ("Regions");
1299 Glib::Threads::Mutex::Lock rl (region_lock);
1300 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1301 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1302 boost::shared_ptr<Region> r = i->second;
1303 /* only store regions not attached to playlists */
1304 if (r->playlist() == 0) {
1305 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1306 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1308 child->add_child_nocopy (r->get_state ());
1313 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1315 if (!cassocs.empty()) {
1316 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1318 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1319 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1320 can->set_property (X_("copy"), i->first->id());
1321 can->set_property (X_("original"), i->second->id());
1322 ca->add_child_nocopy (*can);
1329 node->add_child_nocopy (_selection->get_state());
1332 node->add_child_nocopy (_locations->get_state());
1335 Locations loc (*this);
1336 const bool was_dirty = dirty();
1337 // for a template, just create a new Locations, populate it
1338 // with the default start and end, and get the state for that.
1339 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1340 range->set (max_samplepos, 0);
1342 XMLNode& locations_state = loc.get_state();
1344 if (ARDOUR::Profile->get_trx() && _locations) {
1345 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1346 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1347 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1348 locations_state.add_child_nocopy ((*i)->get_state ());
1352 node->add_child_nocopy (locations_state);
1354 /* adding a location above will have marked the session
1355 * dirty. This is an artifact, so fix it if the session wasn't
1360 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1364 child = node->add_child ("Bundles");
1366 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1367 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1368 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1370 child->add_child_nocopy (b->get_state());
1375 node->add_child_nocopy (_vca_manager->get_state());
1377 child = node->add_child ("Routes");
1379 boost::shared_ptr<RouteList> r = routes.reader ();
1381 route_id_compare cmp;
1382 RouteList xml_node_order (*r);
1383 xml_node_order.sort (cmp);
1385 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1386 if (!(*i)->is_auditioner()) {
1388 child->add_child_nocopy ((*i)->get_state());
1390 child->add_child_nocopy ((*i)->get_template());
1396 playlists->add_state (node, full_state);
1398 child = node->add_child ("RouteGroups");
1399 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1400 child->add_child_nocopy ((*i)->get_state());
1404 XMLNode* gain_child = node->add_child ("Click");
1405 gain_child->add_child_nocopy (_click_io->state (full_state));
1406 gain_child->add_child_nocopy (_click_gain->state (full_state));
1410 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1411 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1415 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1416 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1419 node->add_child_nocopy (_speakers->get_state());
1420 node->add_child_nocopy (_tempo_map->get_state());
1421 node->add_child_nocopy (get_control_protocol_state());
1424 node->add_child_copy (*_extra_xml);
1428 Glib::Threads::Mutex::Lock lm (lua_lock);
1431 luabridge::LuaRef savedstate ((*_lua_save)());
1432 saved = savedstate.cast<std::string>();
1434 lua.collect_garbage ();
1437 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1438 std::string b64s (b64);
1441 XMLNode* script_node = new XMLNode (X_("Script"));
1442 script_node->set_property (X_("lua"), LUA_VERSION);
1443 script_node->add_content (b64s);
1444 node->add_child_nocopy (*script_node);
1451 Session::get_control_protocol_state ()
1453 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1454 return cpm.get_state();
1458 Session::set_state (const XMLNode& node, int version)
1465 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1467 if (node.name() != X_("Session")) {
1468 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1472 node.get_property ("name", _name);
1474 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1476 _nominal_sample_rate = _base_sample_rate;
1478 assert (AudioEngine::instance()->running ());
1479 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1480 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1481 if (r.get_value_or (0)) {
1487 created_with = "unknown";
1488 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1489 child->get_property (X_("created-with"), created_with);
1492 setup_raid_path(_session_dir->root_path());
1494 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1497 if (node.get_property (X_("id-counter"), counter)) {
1498 ID::init_counter (counter);
1500 /* old sessions used a timebased counter, so fake
1501 * the startup ID counter based on a standard
1506 ID::init_counter (now);
1509 if (node.get_property (X_("name-counter"), counter)) {
1510 init_name_id_counter (counter);
1513 if (node.get_property (X_("event-counter"), counter)) {
1514 Evoral::init_event_id_counter (counter);
1517 if (node.get_property (X_("vca-counter"), counter)) {
1518 VCA::set_next_vca_number (counter);
1520 VCA::set_next_vca_number (1);
1523 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1524 _midi_ports->set_midi_port_states (child->children());
1527 IO::disable_connecting ();
1529 Stateful::save_extra_xml (node);
1531 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1532 load_options (*child);
1533 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1534 load_options (*child);
1536 error << _("Session: XML state has no options section") << endmsg;
1539 if (version >= 3000) {
1540 if ((child = find_named_node (node, "Metadata")) == 0) {
1541 warning << _("Session: XML state has no metadata section") << endmsg;
1542 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1547 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1548 _speakers->set_state (*child, version);
1551 if ((child = find_named_node (node, "Sources")) == 0) {
1552 error << _("Session: XML state has no sources section") << endmsg;
1554 } else if (load_sources (*child)) {
1558 if ((child = find_named_node (node, "TempoMap")) == 0) {
1559 error << _("Session: XML state has no Tempo Map section") << endmsg;
1561 } else if (_tempo_map->set_state (*child, version)) {
1565 if ((child = find_named_node (node, "Locations")) == 0) {
1566 error << _("Session: XML state has no locations section") << endmsg;
1568 } else if (_locations->set_state (*child, version)) {
1572 locations_changed ();
1574 if (_session_range_location) {
1575 AudioFileSource::set_header_position_offset (_session_range_location->start());
1578 if ((child = find_named_node (node, "Regions")) == 0) {
1579 error << _("Session: XML state has no Regions section") << endmsg;
1581 } else if (load_regions (*child)) {
1585 if ((child = find_named_node (node, "Playlists")) == 0) {
1586 error << _("Session: XML state has no playlists section") << endmsg;
1588 } else if (playlists->load (*this, *child)) {
1592 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1594 } else if (playlists->load_unused (*this, *child)) {
1598 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1599 if (load_compounds (*child)) {
1604 if (version >= 3000) {
1605 if ((child = find_named_node (node, "Bundles")) == 0) {
1606 warning << _("Session: XML state has no bundles section") << endmsg;
1609 /* We can't load Bundles yet as they need to be able
1610 * to convert from port names to Port objects, which can't happen until
1612 _bundle_xml_node = new XMLNode (*child);
1616 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1617 _vca_manager->set_state (*child, version);
1620 if ((child = find_named_node (node, "Routes")) == 0) {
1621 error << _("Session: XML state has no routes section") << endmsg;
1623 } else if (load_routes (*child, version)) {
1627 /* Now that we have Routes and masters loaded, connect them if appropriate */
1629 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1631 if (version >= 3000) {
1633 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1634 error << _("Session: XML state has no route groups section") << endmsg;
1636 } else if (load_route_groups (*child, version)) {
1640 } else if (version < 3000) {
1642 if ((child = find_named_node (node, "EditGroups")) == 0) {
1643 error << _("Session: XML state has no edit groups section") << endmsg;
1645 } else if (load_route_groups (*child, version)) {
1649 if ((child = find_named_node (node, "MixGroups")) == 0) {
1650 error << _("Session: XML state has no mix groups section") << endmsg;
1652 } else if (load_route_groups (*child, version)) {
1657 if ((child = find_named_node (node, "Click")) == 0) {
1658 warning << _("Session: XML state has no click section") << endmsg;
1659 } else if (_click_io) {
1660 setup_click_state (&node);
1663 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1664 ControlProtocolManager::instance().set_state (*child, version);
1667 if ((child = find_named_node (node, "Script"))) {
1668 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1669 if (!(*n)->is_content ()) { continue; }
1671 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1673 Glib::Threads::Mutex::Lock lm (lua_lock);
1674 (*_lua_load)(std::string ((const char*)buf, size));
1675 } catch (luabridge::LuaException const& e) {
1676 cerr << "LuaException:" << e.what () << endl;
1682 if ((child = find_named_node (node, X_("Selection")))) {
1683 _selection->set_state (*child, version);
1686 update_route_record_state ();
1688 /* here beginneth the second phase ... */
1689 set_snapshot_name (_current_snapshot_name);
1691 StateReady (); /* EMIT SIGNAL */
1704 Session::load_routes (const XMLNode& node, int version)
1707 XMLNodeConstIterator niter;
1708 RouteList new_routes;
1710 nlist = node.children();
1714 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1716 boost::shared_ptr<Route> route;
1718 if (version < 3000) {
1719 route = XMLRouteFactory_2X (**niter, version);
1720 } else if (version < 5000) {
1721 route = XMLRouteFactory_3X (**niter, version);
1723 route = XMLRouteFactory (**niter, version);
1727 error << _("Session: cannot create Route from XML description.") << endmsg;
1731 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1733 new_routes.push_back (route);
1736 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1738 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1740 BootMessage (_("Finished adding tracks/busses"));
1745 boost::shared_ptr<Route>
1746 Session::XMLRouteFactory (const XMLNode& node, int version)
1748 boost::shared_ptr<Route> ret;
1750 if (node.name() != "Route") {
1754 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1757 pl_prop = node.property (X_("midi-playlist"));
1760 DataType type = DataType::AUDIO;
1761 node.get_property("default-type", type);
1763 assert (type != DataType::NIL);
1767 /* has at least 1 playlist, therefore a track ... */
1769 boost::shared_ptr<Track> track;
1771 if (type == DataType::AUDIO) {
1772 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1774 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1777 if (track->init()) {
1781 if (track->set_state (node, version)) {
1785 BOOST_MARK_TRACK (track);
1789 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1790 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1793 if (r->init () == 0 && r->set_state (node, version) == 0) {
1794 BOOST_MARK_ROUTE (r);
1802 boost::shared_ptr<Route>
1803 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1805 boost::shared_ptr<Route> ret;
1807 if (node.name() != "Route") {
1811 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1813 DataType type = DataType::AUDIO;
1814 node.get_property("default-type", type);
1816 assert (type != DataType::NIL);
1820 boost::shared_ptr<Track> track;
1822 if (type == DataType::AUDIO) {
1823 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1825 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1828 if (track->init()) {
1832 if (track->set_state (node, version)) {
1836 BOOST_MARK_TRACK (track);
1840 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1841 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1843 if (r->init () == 0 && r->set_state (node, version) == 0) {
1844 BOOST_MARK_ROUTE (r);
1852 boost::shared_ptr<Route>
1853 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1855 boost::shared_ptr<Route> ret;
1857 if (node.name() != "Route") {
1861 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1863 ds_prop = node.property (X_("diskstream"));
1866 DataType type = DataType::AUDIO;
1867 node.get_property("default-type", type);
1869 assert (type != DataType::NIL);
1873 /* see comment in current ::set_state() regarding diskstream
1874 * state and DiskReader/DiskWRiter.
1877 error << _("Could not find diskstream for route") << endmsg;
1878 return boost::shared_ptr<Route> ();
1880 boost::shared_ptr<Track> track;
1882 if (type == DataType::AUDIO) {
1883 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1885 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1888 if (track->init()) {
1892 if (track->set_state (node, version)) {
1896 BOOST_MARK_TRACK (track);
1900 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1901 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1903 if (r->init () == 0 && r->set_state (node, version) == 0) {
1904 BOOST_MARK_ROUTE (r);
1913 Session::load_regions (const XMLNode& node)
1916 XMLNodeConstIterator niter;
1917 boost::shared_ptr<Region> region;
1919 nlist = node.children();
1923 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1924 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1925 error << _("Session: cannot create Region from XML description.");
1926 XMLProperty const * name = (**niter).property("name");
1929 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1940 Session::load_compounds (const XMLNode& node)
1942 XMLNodeList calist = node.children();
1943 XMLNodeConstIterator caiter;
1944 XMLProperty const * caprop;
1946 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1947 XMLNode* ca = *caiter;
1951 if ((caprop = ca->property (X_("original"))) == 0) {
1954 orig_id = caprop->value();
1956 if ((caprop = ca->property (X_("copy"))) == 0) {
1959 copy_id = caprop->value();
1961 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1962 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1964 if (!orig || !copy) {
1965 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1971 RegionFactory::add_compound_association (orig, copy);
1978 Session::load_nested_sources (const XMLNode& node)
1981 XMLNodeConstIterator niter;
1983 nlist = node.children();
1985 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1986 if ((*niter)->name() == "Source") {
1988 /* it may already exist, so don't recreate it unnecessarily
1991 XMLProperty const * prop = (*niter)->property (X_("id"));
1993 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1997 ID source_id (prop->value());
1999 if (!source_by_id (source_id)) {
2002 SourceFactory::create (*this, **niter, true);
2004 catch (failed_constructor& err) {
2005 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2012 boost::shared_ptr<Region>
2013 Session::XMLRegionFactory (const XMLNode& node, bool full)
2015 XMLProperty const * type = node.property("type");
2019 const XMLNodeList& nlist = node.children();
2021 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2022 XMLNode *child = (*niter);
2023 if (child->name() == "NestedSource") {
2024 load_nested_sources (*child);
2028 if (!type || type->value() == "audio") {
2029 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2030 } else if (type->value() == "midi") {
2031 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2034 } catch (failed_constructor& err) {
2035 return boost::shared_ptr<Region> ();
2038 return boost::shared_ptr<Region> ();
2041 boost::shared_ptr<AudioRegion>
2042 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2044 XMLProperty const * prop;
2045 boost::shared_ptr<Source> source;
2046 boost::shared_ptr<AudioSource> as;
2048 SourceList master_sources;
2049 uint32_t nchans = 1;
2052 if (node.name() != X_("Region")) {
2053 return boost::shared_ptr<AudioRegion>();
2056 node.get_property (X_("channels"), nchans);
2058 if ((prop = node.property ("name")) == 0) {
2059 cerr << "no name for this region\n";
2063 if ((prop = node.property (X_("source-0"))) == 0) {
2064 if ((prop = node.property ("source")) == 0) {
2065 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2066 return boost::shared_ptr<AudioRegion>();
2070 PBD::ID s_id (prop->value());
2072 if ((source = source_by_id (s_id)) == 0) {
2073 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2074 return boost::shared_ptr<AudioRegion>();
2077 as = boost::dynamic_pointer_cast<AudioSource>(source);
2079 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2080 return boost::shared_ptr<AudioRegion>();
2083 sources.push_back (as);
2085 /* pickup other channels */
2087 for (uint32_t n=1; n < nchans; ++n) {
2088 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2089 if ((prop = node.property (buf)) != 0) {
2091 PBD::ID id2 (prop->value());
2093 if ((source = source_by_id (id2)) == 0) {
2094 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2095 return boost::shared_ptr<AudioRegion>();
2098 as = boost::dynamic_pointer_cast<AudioSource>(source);
2100 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2101 return boost::shared_ptr<AudioRegion>();
2103 sources.push_back (as);
2107 for (uint32_t n = 0; n < nchans; ++n) {
2108 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2109 if ((prop = node.property (buf)) != 0) {
2111 PBD::ID id2 (prop->value());
2113 if ((source = source_by_id (id2)) == 0) {
2114 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2115 return boost::shared_ptr<AudioRegion>();
2118 as = boost::dynamic_pointer_cast<AudioSource>(source);
2120 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2121 return boost::shared_ptr<AudioRegion>();
2123 master_sources.push_back (as);
2128 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2130 /* a final detail: this is the one and only place that we know how long missing files are */
2132 if (region->whole_file()) {
2133 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2134 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2136 sfp->set_length (region->length());
2141 if (!master_sources.empty()) {
2142 if (master_sources.size() != nchans) {
2143 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2145 region->set_master_sources (master_sources);
2153 catch (failed_constructor& err) {
2154 return boost::shared_ptr<AudioRegion>();
2158 boost::shared_ptr<MidiRegion>
2159 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2161 XMLProperty const * prop;
2162 boost::shared_ptr<Source> source;
2163 boost::shared_ptr<MidiSource> ms;
2166 if (node.name() != X_("Region")) {
2167 return boost::shared_ptr<MidiRegion>();
2170 if ((prop = node.property ("name")) == 0) {
2171 cerr << "no name for this region\n";
2175 if ((prop = node.property (X_("source-0"))) == 0) {
2176 if ((prop = node.property ("source")) == 0) {
2177 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2178 return boost::shared_ptr<MidiRegion>();
2182 PBD::ID s_id (prop->value());
2184 if ((source = source_by_id (s_id)) == 0) {
2185 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2186 return boost::shared_ptr<MidiRegion>();
2189 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2191 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2192 return boost::shared_ptr<MidiRegion>();
2195 sources.push_back (ms);
2198 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2199 /* a final detail: this is the one and only place that we know how long missing files are */
2201 if (region->whole_file()) {
2202 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2203 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2205 sfp->set_length (region->length());
2213 catch (failed_constructor& err) {
2214 return boost::shared_ptr<MidiRegion>();
2219 Session::get_sources_as_xml ()
2222 XMLNode* node = new XMLNode (X_("Sources"));
2223 Glib::Threads::Mutex::Lock lm (source_lock);
2225 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2226 node->add_child_nocopy (i->second->get_state());
2233 Session::reset_write_sources (bool mark_write_complete, bool force)
2235 boost::shared_ptr<RouteList> rl = routes.reader();
2236 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2237 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2239 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2240 tr->reset_write_sources(mark_write_complete, force);
2241 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2247 Session::load_sources (const XMLNode& node)
2250 XMLNodeConstIterator niter;
2251 /* don't need this but it stops some
2252 * versions of gcc complaining about
2253 * discarded return values.
2255 boost::shared_ptr<Source> source;
2257 nlist = node.children();
2260 std::map<std::string, std::string> relocation;
2262 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2263 #ifdef PLATFORM_WINDOWS
2267 XMLNode srcnode (**niter);
2268 bool try_replace_abspath = true;
2272 #ifdef PLATFORM_WINDOWS
2273 // do not show "insert media" popups (files embedded from removable media).
2274 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2276 if ((source = XMLSourceFactory (srcnode)) == 0) {
2277 error << _("Session: cannot create Source from XML description.") << endmsg;
2279 #ifdef PLATFORM_WINDOWS
2280 SetErrorMode(old_mode);
2283 } catch (MissingSource& err) {
2284 #ifdef PLATFORM_WINDOWS
2285 SetErrorMode(old_mode);
2288 /* try previous abs path replacements first */
2289 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2290 std::string dir = Glib::path_get_dirname (err.path);
2291 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2292 if (rl != relocation.end ()) {
2293 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2294 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2295 srcnode.set_property ("origin", newpath);
2296 try_replace_abspath = false;
2303 _missing_file_replacement = "";
2305 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2306 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2307 PROGRAM_NAME) << endmsg;
2311 if (!no_questions_about_missing_files) {
2312 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2317 switch (user_choice) {
2319 /* user added a new search location
2320 * or selected a new absolute path,
2322 if (Glib::path_is_absolute (err.path)) {
2323 if (!_missing_file_replacement.empty ()) {
2324 /* replace origin, in XML */
2325 std::string newpath = Glib::build_filename (
2326 _missing_file_replacement, Glib::path_get_basename (err.path));
2327 srcnode.set_property ("origin", newpath);
2328 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2329 _missing_file_replacement = "";
2336 /* user asked to quit the entire session load */
2340 no_questions_about_missing_files = true;
2344 no_questions_about_missing_files = true;
2351 case DataType::AUDIO:
2352 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2355 case DataType::MIDI:
2356 /* The MIDI file is actually missing so
2357 * just create a new one in the same
2358 * location. Do not announce its
2362 if (!Glib::path_is_absolute (err.path)) {
2363 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2365 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2370 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2371 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2372 /* reset ID to match the missing one */
2373 source->set_id (**niter);
2374 /* Now we can announce it */
2375 SourceFactory::SourceCreated (source);
2386 boost::shared_ptr<Source>
2387 Session::XMLSourceFactory (const XMLNode& node)
2389 if (node.name() != "Source") {
2390 return boost::shared_ptr<Source>();
2394 /* note: do peak building in another thread when loading session state */
2395 return SourceFactory::create (*this, node, true);
2398 catch (failed_constructor& err) {
2399 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2400 return boost::shared_ptr<Source>();
2405 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2407 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2411 bool absolute_path = Glib::path_is_absolute (template_name);
2413 /* directory to put the template in */
2414 std::string template_dir_path;
2416 if (!absolute_path) {
2417 std::string user_template_dir(user_template_directory());
2419 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2420 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2421 user_template_dir, g_strerror (errno)) << endmsg;
2425 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2427 template_dir_path = template_name;
2430 if (!ARDOUR::Profile->get_trx()) {
2431 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2432 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2433 template_dir_path) << endmsg;
2437 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2438 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2439 template_dir_path, g_strerror (errno)) << endmsg;
2445 std::string template_file_path;
2447 if (ARDOUR::Profile->get_trx()) {
2448 template_file_path = template_name;
2450 if (absolute_path) {
2451 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2453 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2457 SessionSaveUnderway (); /* EMIT SIGNAL */
2462 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2463 root = &get_template ();
2466 root->remove_nodes_and_delete (X_("description"));
2468 if (!description.empty()) {
2469 XMLNode* desc = new XMLNode (X_("description"));
2470 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2471 desc->add_child_nocopy (*desc_cont);
2473 root->add_child_nocopy (*desc);
2476 tree.set_root (root);
2478 if (!tree.write (template_file_path)) {
2479 error << _("template not saved") << endmsg;
2483 store_recent_templates (template_file_path);
2489 Session::refresh_disk_space ()
2491 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2493 Glib::Threads::Mutex::Lock lm (space_lock);
2495 /* get freespace on every FS that is part of the session path */
2497 _total_free_4k_blocks = 0;
2498 _total_free_4k_blocks_uncertain = false;
2500 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2501 #if defined(__NetBSD__)
2502 struct statvfs statfsbuf;
2504 statvfs (i->path.c_str(), &statfsbuf);
2506 struct statfs statfsbuf;
2508 statfs (i->path.c_str(), &statfsbuf);
2510 double const scale = statfsbuf.f_bsize / 4096.0;
2512 /* See if this filesystem is read-only */
2513 struct statvfs statvfsbuf;
2514 statvfs (i->path.c_str(), &statvfsbuf);
2516 /* f_bavail can be 0 if it is undefined for whatever
2517 filesystem we are looking at; Samba shares mounted
2518 via GVFS are an example of this.
2520 if (statfsbuf.f_bavail == 0) {
2521 /* block count unknown */
2523 i->blocks_unknown = true;
2524 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2525 /* read-only filesystem */
2527 i->blocks_unknown = false;
2529 /* read/write filesystem with known space */
2530 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2531 i->blocks_unknown = false;
2534 _total_free_4k_blocks += i->blocks;
2535 if (i->blocks_unknown) {
2536 _total_free_4k_blocks_uncertain = true;
2539 #elif defined PLATFORM_WINDOWS
2540 vector<string> scanned_volumes;
2541 vector<string>::iterator j;
2542 vector<space_and_path>::iterator i;
2543 DWORD nSectorsPerCluster, nBytesPerSector,
2544 nFreeClusters, nTotalClusters;
2548 _total_free_4k_blocks = 0;
2550 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2551 strncpy (disk_drive, (*i).path.c_str(), 3);
2555 volume_found = false;
2556 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2558 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2559 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2560 i->blocks = (uint32_t)(nFreeBytes / 4096);
2562 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2563 if (0 == j->compare(disk_drive)) {
2564 volume_found = true;
2569 if (!volume_found) {
2570 scanned_volumes.push_back(disk_drive);
2571 _total_free_4k_blocks += i->blocks;
2576 if (0 == _total_free_4k_blocks) {
2577 strncpy (disk_drive, path().c_str(), 3);
2580 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2582 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2583 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2584 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2591 Session::get_best_session_directory_for_new_audio ()
2593 vector<space_and_path>::iterator i;
2594 string result = _session_dir->root_path();
2596 /* handle common case without system calls */
2598 if (session_dirs.size() == 1) {
2602 /* OK, here's the algorithm we're following here:
2604 We want to select which directory to use for
2605 the next file source to be created. Ideally,
2606 we'd like to use a round-robin process so as to
2607 get maximum performance benefits from splitting
2608 the files across multiple disks.
2610 However, in situations without much diskspace, an
2611 RR approach may end up filling up a filesystem
2612 with new files while others still have space.
2613 Its therefore important to pay some attention to
2614 the freespace in the filesystem holding each
2615 directory as well. However, if we did that by
2616 itself, we'd keep creating new files in the file
2617 system with the most space until it was as full
2618 as all others, thus negating any performance
2619 benefits of this RAID-1 like approach.
2621 So, we use a user-configurable space threshold. If
2622 there are at least 2 filesystems with more than this
2623 much space available, we use RR selection between them.
2624 If not, then we pick the filesystem with the most space.
2626 This gets a good balance between the two
2630 refresh_disk_space ();
2632 int free_enough = 0;
2634 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2635 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2640 if (free_enough >= 2) {
2641 /* use RR selection process, ensuring that the one
2645 i = last_rr_session_dir;
2648 if (++i == session_dirs.end()) {
2649 i = session_dirs.begin();
2652 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2653 SessionDirectory sdir(i->path);
2654 if (sdir.create ()) {
2656 last_rr_session_dir = i;
2661 } while (i != last_rr_session_dir);
2665 /* pick FS with the most freespace (and that
2666 seems to actually work ...)
2669 vector<space_and_path> sorted;
2670 space_and_path_ascending_cmp cmp;
2672 sorted = session_dirs;
2673 sort (sorted.begin(), sorted.end(), cmp);
2675 for (i = sorted.begin(); i != sorted.end(); ++i) {
2676 SessionDirectory sdir(i->path);
2677 if (sdir.create ()) {
2679 last_rr_session_dir = i;
2689 Session::automation_dir () const
2691 return Glib::build_filename (_path, automation_dir_name);
2695 Session::analysis_dir () const
2697 return Glib::build_filename (_path, analysis_dir_name);
2701 Session::plugins_dir () const
2703 return Glib::build_filename (_path, plugins_dir_name);
2707 Session::externals_dir () const
2709 return Glib::build_filename (_path, externals_dir_name);
2713 Session::load_bundles (XMLNode const & node)
2715 XMLNodeList nlist = node.children();
2716 XMLNodeConstIterator niter;
2720 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2721 if ((*niter)->name() == "InputBundle") {
2722 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2723 } else if ((*niter)->name() == "OutputBundle") {
2724 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2726 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2735 Session::load_route_groups (const XMLNode& node, int version)
2737 XMLNodeList nlist = node.children();
2738 XMLNodeConstIterator niter;
2742 if (version >= 3000) {
2744 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2745 if ((*niter)->name() == "RouteGroup") {
2746 RouteGroup* rg = new RouteGroup (*this, "");
2747 add_route_group (rg);
2748 rg->set_state (**niter, version);
2752 } else if (version < 3000) {
2754 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2755 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2756 RouteGroup* rg = new RouteGroup (*this, "");
2757 add_route_group (rg);
2758 rg->set_state (**niter, version);
2767 state_file_filter (const string &str, void* /*arg*/)
2769 return (str.length() > strlen(statefile_suffix) &&
2770 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2774 remove_end(string state)
2776 string statename(state);
2778 string::size_type start,end;
2779 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2780 statename = statename.substr (start+1);
2783 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2784 end = statename.length();
2787 return string(statename.substr (0, end));
2791 Session::possible_states (string path)
2793 vector<string> states;
2794 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2796 transform(states.begin(), states.end(), states.begin(), remove_end);
2798 sort (states.begin(), states.end());
2804 Session::possible_states () const
2806 return possible_states(_path);
2810 Session::new_route_group (const std::string& name)
2812 RouteGroup* rg = NULL;
2814 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2815 if ((*i)->name () == name) {
2822 rg = new RouteGroup (*this, name);
2823 add_route_group (rg);
2829 Session::add_route_group (RouteGroup* g)
2831 _route_groups.push_back (g);
2832 route_group_added (g); /* EMIT SIGNAL */
2834 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2835 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2836 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2842 Session::remove_route_group (RouteGroup& rg)
2844 list<RouteGroup*>::iterator i;
2846 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2847 _route_groups.erase (i);
2850 route_group_removed (); /* EMIT SIGNAL */
2854 /** Set a new order for our route groups, without adding or removing any.
2855 * @param groups Route group list in the new order.
2858 Session::reorder_route_groups (list<RouteGroup*> groups)
2860 _route_groups = groups;
2862 route_groups_reordered (); /* EMIT SIGNAL */
2868 Session::route_group_by_name (string name)
2870 list<RouteGroup *>::iterator i;
2872 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2873 if ((*i)->name() == name) {
2881 Session::all_route_group() const
2883 return *_all_route_group;
2887 Session::add_commands (vector<Command*> const & cmds)
2889 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2895 Session::add_command (Command* const cmd)
2897 assert (_current_trans);
2898 DEBUG_UNDO_HISTORY (
2899 string_compose ("Current Undo Transaction %1, adding command: %2",
2900 _current_trans->name (),
2902 _current_trans->add_command (cmd);
2905 PBD::StatefulDiffCommand*
2906 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2908 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2914 Session::begin_reversible_command (const string& name)
2916 begin_reversible_command (g_quark_from_string (name.c_str ()));
2919 /** Begin a reversible command using a GQuark to identify it.
2920 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2921 * but there must be as many begin...()s as there are commit...()s.
2924 Session::begin_reversible_command (GQuark q)
2926 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2927 to hold all the commands that are committed. This keeps the order of
2928 commands correct in the history.
2931 if (_current_trans == 0) {
2932 DEBUG_UNDO_HISTORY (string_compose (
2933 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2935 /* start a new transaction */
2936 assert (_current_trans_quarks.empty ());
2937 _current_trans = new UndoTransaction();
2938 _current_trans->set_name (g_quark_to_string (q));
2940 DEBUG_UNDO_HISTORY (
2941 string_compose ("Begin Reversible Command, current transaction: %1",
2942 _current_trans->name ()));
2945 _current_trans_quarks.push_front (q);
2949 Session::abort_reversible_command ()
2951 if (_current_trans != 0) {
2952 DEBUG_UNDO_HISTORY (
2953 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2954 _current_trans->clear();
2955 delete _current_trans;
2957 _current_trans_quarks.clear();
2962 Session::commit_reversible_command (Command *cmd)
2964 assert (_current_trans);
2965 assert (!_current_trans_quarks.empty ());
2970 DEBUG_UNDO_HISTORY (
2971 string_compose ("Current Undo Transaction %1, adding command: %2",
2972 _current_trans->name (),
2974 _current_trans->add_command (cmd);
2977 DEBUG_UNDO_HISTORY (
2978 string_compose ("Commit Reversible Command, current transaction: %1",
2979 _current_trans->name ()));
2981 _current_trans_quarks.pop_front ();
2983 if (!_current_trans_quarks.empty ()) {
2984 DEBUG_UNDO_HISTORY (
2985 string_compose ("Commit Reversible Command, transaction is not "
2986 "top-level, current transaction: %1",
2987 _current_trans->name ()));
2988 /* the transaction we're committing is not the top-level one */
2992 if (_current_trans->empty()) {
2993 /* no commands were added to the transaction, so just get rid of it */
2994 DEBUG_UNDO_HISTORY (
2995 string_compose ("Commit Reversible Command, No commands were "
2996 "added to current transaction: %1",
2997 _current_trans->name ()));
2998 delete _current_trans;
3003 gettimeofday (&now, 0);
3004 _current_trans->set_timestamp (now);
3006 _history.add (_current_trans);
3011 accept_all_audio_files (const string& path, void* /*arg*/)
3013 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3017 if (!AudioFileSource::safe_audio_file_extension (path)) {
3025 accept_all_midi_files (const string& path, void* /*arg*/)
3027 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3031 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3032 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3033 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3037 accept_all_state_files (const string& path, void* /*arg*/)
3039 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3043 std::string const statefile_ext (statefile_suffix);
3044 if (path.length() >= statefile_ext.length()) {
3045 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3052 Session::find_all_sources (string path, set<string>& result)
3057 if (!tree.read (path)) {
3061 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3066 XMLNodeConstIterator niter;
3068 nlist = node->children();
3072 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3074 XMLProperty const * prop;
3076 if ((prop = (*niter)->property (X_("type"))) == 0) {
3080 DataType type (prop->value());
3082 if ((prop = (*niter)->property (X_("name"))) == 0) {
3086 if (Glib::path_is_absolute (prop->value())) {
3087 /* external file, ignore */
3095 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3096 result.insert (found_path);
3104 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3106 vector<string> state_files;
3108 string this_snapshot_path;
3114 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3115 ripped = ripped.substr (0, ripped.length() - 1);
3118 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3120 if (state_files.empty()) {
3125 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3126 this_snapshot_path += statefile_suffix;
3128 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3130 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3132 if (exclude_this_snapshot && *i == this_snapshot_path) {
3133 cerr << "\texcluded\n";
3138 if (find_all_sources (*i, result) < 0) {
3146 struct RegionCounter {
3147 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3148 AudioSourceList::iterator iter;
3149 boost::shared_ptr<Region> region;
3152 RegionCounter() : count (0) {}
3156 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3158 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3159 return r.get_value_or (1);
3163 Session::cleanup_regions ()
3165 bool removed = false;
3166 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3168 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3170 uint32_t used = playlists->region_use_count (i->second);
3172 if (used == 0 && !i->second->automatic ()) {
3173 boost::weak_ptr<Region> w = i->second;
3176 RegionFactory::map_remove (w);
3183 // re-check to remove parent references of compound regions
3184 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3185 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3189 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3190 if (0 == playlists->region_use_count (i->second)) {
3191 boost::weak_ptr<Region> w = i->second;
3193 RegionFactory::map_remove (w);
3200 /* dump the history list */
3207 Session::can_cleanup_peakfiles () const
3209 if (deletion_in_progress()) {
3212 if (!_writable || (_state_of_the_state & CannotSave)) {
3213 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3216 if (record_status() == Recording) {
3217 error << _("Cannot cleanup peak-files while recording") << endmsg;
3224 Session::cleanup_peakfiles ()
3226 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3231 assert (can_cleanup_peakfiles ());
3232 assert (!peaks_cleanup_in_progres());
3234 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3236 int timeout = 5000; // 5 seconds
3237 while (!SourceFactory::files_with_peaks.empty()) {
3238 Glib::usleep (1000);
3239 if (--timeout < 0) {
3240 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3241 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3246 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3247 boost::shared_ptr<AudioSource> as;
3248 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3249 as->close_peakfile();
3253 PBD::clear_directory (session_directory().peak_path());
3255 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3257 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3258 boost::shared_ptr<AudioSource> as;
3259 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3260 SourceFactory::setup_peakfile(as, true);
3267 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3269 pl->deep_sources (*all_sources);
3273 Session::cleanup_sources (CleanupReport& rep)
3275 // FIXME: needs adaptation to midi
3277 vector<boost::shared_ptr<Source> > dead_sources;
3280 vector<string> candidates;
3281 vector<string> unused;
3282 set<string> sources_used_by_all_snapshots;
3289 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3291 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3293 /* this is mostly for windows which doesn't allow file
3294 * renaming if the file is in use. But we don't special
3295 * case it because we need to know if this causes
3296 * problems, and the easiest way to notice that is to
3297 * keep it in place for all platforms.
3300 request_stop (false);
3302 _butler->wait_until_finished ();
3304 /* consider deleting all unused playlists */
3306 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3311 /* sync the "all regions" property of each playlist with its current state */
3313 playlists->sync_all_regions_with_regions ();
3315 /* find all un-used sources */
3320 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3322 SourceMap::iterator tmp;
3327 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3331 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3332 dead_sources.push_back (i->second);
3333 i->second->drop_references ();
3339 /* build a list of all the possible audio directories for the session */
3341 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3342 SessionDirectory sdir ((*i).path);
3343 asp += sdir.sound_path();
3345 audio_path += asp.to_string();
3348 /* build a list of all the possible midi directories for the session */
3350 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3351 SessionDirectory sdir ((*i).path);
3352 msp += sdir.midi_path();
3354 midi_path += msp.to_string();
3356 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3357 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3359 /* add sources from all other snapshots as "used", but don't use this
3360 snapshot because the state file on disk still references sources we
3361 may have already dropped.
3364 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3366 /* Although the region factory has a list of all regions ever created
3367 * for this session, we're only interested in regions actually in
3368 * playlists right now. So merge all playlist regions lists together.
3370 * This will include the playlists used within compound regions.
3373 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3375 /* add our current source list
3378 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3379 boost::shared_ptr<FileSource> fs;
3380 SourceMap::iterator tmp = i;
3383 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3389 /* this is mostly for windows which doesn't allow file
3390 * renaming if the file is in use. But we do not special
3391 * case it because we need to know if this causes
3392 * problems, and the easiest way to notice that is to
3393 * keep it in place for all platforms.
3398 if (!fs->is_stub()) {
3400 /* Note that we're checking a list of all
3401 * sources across all snapshots with the list
3402 * of sources used by this snapshot.
3405 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3406 /* this source is in use by this snapshot */
3407 sources_used_by_all_snapshots.insert (fs->path());
3408 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3410 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3411 /* this source is NOT in use by this snapshot */
3413 /* remove all related regions from RegionFactory master list */
3415 RegionFactory::remove_regions_using_source (i->second);
3417 /* remove from our current source list
3418 * also. We may not remove it from
3419 * disk, because it may be used by
3420 * other snapshots, but it isn't used inside this
3421 * snapshot anymore, so we don't need a
3432 /* now check each candidate source to see if it exists in the list of
3433 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3436 cerr << "Candidates: " << candidates.size() << endl;
3437 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3439 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3444 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3446 tmppath1 = canonical_path (spath);
3447 tmppath2 = canonical_path ((*i));
3449 cerr << "\t => " << tmppath2 << endl;
3451 if (tmppath1 == tmppath2) {
3458 unused.push_back (spath);
3462 cerr << "Actually unused: " << unused.size() << endl;
3464 if (unused.empty()) {
3470 /* now try to move all unused files into the "dead" directory(ies) */
3472 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3477 /* don't move the file across filesystems, just
3478 * stick it in the `dead_dir_name' directory
3479 * on whichever filesystem it was already on.
3482 if ((*x).find ("/sounds/") != string::npos) {
3484 /* old school, go up 1 level */
3486 newpath = Glib::path_get_dirname (*x); // "sounds"
3487 newpath = Glib::path_get_dirname (newpath); // "session-name"
3491 /* new school, go up 4 levels */
3493 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3494 newpath = Glib::path_get_dirname (newpath); // "session-name"
3495 newpath = Glib::path_get_dirname (newpath); // "interchange"
3496 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3499 newpath = Glib::build_filename (newpath, dead_dir_name);
3501 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3502 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3506 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3508 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3510 /* the new path already exists, try versioning */
3512 char buf[PATH_MAX+1];
3516 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3519 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3520 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3524 if (version == 999) {
3525 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3529 newpath = newpath_v;
3534 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3535 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3536 newpath, g_strerror (errno)) << endmsg;
3540 /* see if there an easy to find peakfile for this file, and remove it. */
3542 string base = Glib::path_get_basename (*x);
3543 base += "%A"; /* this is what we add for the channel suffix of all native files,
3544 * or for the first channel of embedded files. it will miss
3545 * some peakfiles for other channels
3547 string peakpath = construct_peak_filepath (base);
3549 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3550 if (::g_unlink (peakpath.c_str ()) != 0) {
3551 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3552 g_strerror (errno)) << endmsg;
3553 /* try to back out */
3554 ::g_rename (newpath.c_str (), _path.c_str ());
3559 rep.paths.push_back (*x);
3560 rep.space += statbuf.st_size;
3563 /* dump the history list */
3567 /* save state so we don't end up a session file
3568 * referring to non-existent sources.
3575 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3581 Session::cleanup_trash_sources (CleanupReport& rep)
3583 // FIXME: needs adaptation for MIDI
3585 vector<space_and_path>::iterator i;
3591 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3593 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3595 clear_directory (dead_dir, &rep.space, &rep.paths);
3602 Session::set_dirty ()
3604 /* return early if there's nothing to do */
3609 /* never mark session dirty during loading */
3610 if (_state_of_the_state & Loading) {
3614 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3615 DirtyChanged(); /* EMIT SIGNAL */
3619 Session::set_clean ()
3621 bool was_dirty = dirty();
3623 _state_of_the_state = Clean;
3626 DirtyChanged(); /* EMIT SIGNAL */
3631 Session::set_deletion_in_progress ()
3633 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3637 Session::clear_deletion_in_progress ()
3639 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3643 Session::add_controllable (boost::shared_ptr<Controllable> c)
3645 /* this adds a controllable to the list managed by the Session.
3646 this is a subset of those managed by the Controllable class
3647 itself, and represents the only ones whose state will be saved
3648 as part of the session.
3651 Glib::Threads::Mutex::Lock lm (controllables_lock);
3652 controllables.insert (c);
3655 struct null_deleter { void operator()(void const *) const {} };
3658 Session::remove_controllable (Controllable* c)
3660 if (_state_of_the_state & Deletion) {
3664 Glib::Threads::Mutex::Lock lm (controllables_lock);
3666 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3668 if (x != controllables.end()) {
3669 controllables.erase (x);
3673 boost::shared_ptr<Controllable>
3674 Session::controllable_by_id (const PBD::ID& id)
3676 Glib::Threads::Mutex::Lock lm (controllables_lock);
3678 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3679 if ((*i)->id() == id) {
3684 return boost::shared_ptr<Controllable>();
3687 boost::shared_ptr<AutomationControl>
3688 Session::automation_control_by_id (const PBD::ID& id)
3690 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3693 boost::shared_ptr<Controllable>
3694 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3696 boost::shared_ptr<Controllable> c;
3697 boost::shared_ptr<Stripable> s;
3698 boost::shared_ptr<Route> r;
3700 switch (desc.top_level_type()) {
3701 case ControllableDescriptor::NamedRoute:
3703 std::string str = desc.top_level_name();
3705 if (str == "Master" || str == "master") {
3707 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3709 } else if (str == "auditioner") {
3712 s = route_by_name (desc.top_level_name());
3718 case ControllableDescriptor::PresentationOrderRoute:
3719 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3722 case ControllableDescriptor::PresentationOrderTrack:
3723 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3726 case ControllableDescriptor::PresentationOrderBus:
3727 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3730 case ControllableDescriptor::PresentationOrderVCA:
3731 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3734 case ControllableDescriptor::SelectionCount:
3735 s = route_by_selected_count (desc.selection_id());
3743 r = boost::dynamic_pointer_cast<Route> (s);
3745 switch (desc.subtype()) {
3746 case ControllableDescriptor::Gain:
3747 c = s->gain_control ();
3750 case ControllableDescriptor::Trim:
3751 c = s->trim_control ();
3754 case ControllableDescriptor::Solo:
3755 c = s->solo_control();
3758 case ControllableDescriptor::Mute:
3759 c = s->mute_control();
3762 case ControllableDescriptor::Recenable:
3763 c = s->rec_enable_control ();
3766 case ControllableDescriptor::PanDirection:
3767 c = s->pan_azimuth_control();
3770 case ControllableDescriptor::PanWidth:
3771 c = s->pan_width_control();
3774 case ControllableDescriptor::PanElevation:
3775 c = s->pan_elevation_control();
3778 case ControllableDescriptor::Balance:
3779 /* XXX simple pan control */
3782 case ControllableDescriptor::PluginParameter:
3784 uint32_t plugin = desc.target (0);
3785 uint32_t parameter_index = desc.target (1);
3787 /* revert to zero based counting */
3793 if (parameter_index > 0) {
3801 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3804 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3805 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3810 case ControllableDescriptor::SendGain: {
3811 uint32_t send = desc.target (0);
3818 c = r->send_level_controllable (send);
3823 /* relax and return a null pointer */
3831 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3834 Stateful::add_instant_xml (node, _path);
3837 if (write_to_config) {
3838 Config->add_instant_xml (node);
3843 Session::instant_xml (const string& node_name)
3845 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3846 if (get_disable_all_loaded_plugins ()) {
3850 return Stateful::instant_xml (node_name, _path);
3854 Session::save_history (string snapshot_name)
3862 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3863 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3867 if (snapshot_name.empty()) {
3868 snapshot_name = _current_snapshot_name;
3871 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3872 const string backup_filename = history_filename + backup_suffix;
3873 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3874 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3876 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3877 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3878 error << _("could not backup old history file, current history not saved") << endmsg;
3883 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3885 if (!tree.write (xml_path))
3887 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3889 if (g_remove (xml_path.c_str()) != 0) {
3890 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3891 xml_path, g_strerror (errno)) << endmsg;
3893 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3894 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3895 backup_path, g_strerror (errno)) << endmsg;
3905 Session::restore_history (string snapshot_name)
3909 if (snapshot_name.empty()) {
3910 snapshot_name = _current_snapshot_name;
3913 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3914 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3916 info << "Loading history from " << xml_path << endmsg;
3918 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3919 info << string_compose (_("%1: no history file \"%2\" for this session."),
3920 _name, xml_path) << endmsg;
3924 if (!tree.read (xml_path)) {
3925 error << string_compose (_("Could not understand session history file \"%1\""),
3926 xml_path) << endmsg;
3933 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3936 UndoTransaction* ut = new UndoTransaction ();
3942 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3943 !t->get_property ("tv-usec", tv_usec)) {
3947 ut->set_name (name);
3951 tv.tv_usec = tv_usec;
3952 ut->set_timestamp(tv);
3954 for (XMLNodeConstIterator child_it = t->children().begin();
3955 child_it != t->children().end(); child_it++)
3957 XMLNode *n = *child_it;
3960 if (n->name() == "MementoCommand" ||
3961 n->name() == "MementoUndoCommand" ||
3962 n->name() == "MementoRedoCommand") {
3964 if ((c = memento_command_factory(n))) {
3968 } else if (n->name() == "NoteDiffCommand") {
3969 PBD::ID id (n->property("midi-source")->value());
3970 boost::shared_ptr<MidiSource> midi_source =
3971 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3973 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3975 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3978 } else if (n->name() == "SysExDiffCommand") {
3980 PBD::ID id (n->property("midi-source")->value());
3981 boost::shared_ptr<MidiSource> midi_source =
3982 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3984 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3986 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3989 } else if (n->name() == "PatchChangeDiffCommand") {
3991 PBD::ID id (n->property("midi-source")->value());
3992 boost::shared_ptr<MidiSource> midi_source =
3993 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3995 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3997 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
4000 } else if (n->name() == "StatefulDiffCommand") {
4001 if ((c = stateful_diff_command_factory (n))) {
4002 ut->add_command (c);
4005 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
4016 Session::config_changed (std::string p, bool ours)
4022 if (p == "seamless-loop") {
4024 } else if (p == "rf-speed") {
4026 } else if (p == "auto-loop") {
4028 } else if (p == "session-monitoring") {
4030 } else if (p == "auto-input") {
4032 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4033 /* auto-input only makes a difference if we're rolling */
4034 set_track_monitor_input_status (!config.get_auto_input());
4037 } else if (p == "punch-in") {
4041 if ((location = _locations->auto_punch_location()) != 0) {
4043 if (config.get_punch_in ()) {
4044 auto_punch_start_changed (location);
4046 clear_events (SessionEvent::PunchIn);
4050 } else if (p == "punch-out") {
4054 if ((location = _locations->auto_punch_location()) != 0) {
4056 if (config.get_punch_out()) {
4057 auto_punch_end_changed (location);
4059 clear_events (SessionEvent::PunchOut);
4063 } else if (p == "edit-mode") {
4065 Glib::Threads::Mutex::Lock lm (playlists->lock);
4067 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4068 (*i)->set_edit_mode (Config->get_edit_mode ());
4071 } else if (p == "use-video-sync") {
4073 waiting_for_sync_offset = config.get_use_video_sync();
4075 } else if (p == "mmc-control") {
4077 //poke_midi_thread ();
4079 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4081 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4083 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4085 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4087 } else if (p == "midi-control") {
4089 //poke_midi_thread ();
4091 } else if (p == "raid-path") {
4093 setup_raid_path (config.get_raid_path());
4095 } else if (p == "timecode-format") {
4099 } else if (p == "video-pullup") {
4103 } else if (p == "seamless-loop") {
4105 if (play_loop && transport_rolling()) {
4106 // to reset diskstreams etc
4107 request_play_loop (true);
4110 } else if (p == "rf-speed") {
4112 cumulative_rf_motion = 0;
4115 } else if (p == "click-sound") {
4117 setup_click_sounds (1);
4119 } else if (p == "click-emphasis-sound") {
4121 setup_click_sounds (-1);
4123 } else if (p == "clicking") {
4125 if (Config->get_clicking()) {
4126 if (_click_io && click_data) { // don't require emphasis data
4133 } else if (p == "click-record-only") {
4135 _click_rec_only = Config->get_click_record_only();
4137 } else if (p == "click-gain") {
4140 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4143 } else if (p == "send-mtc") {
4145 if (Config->get_send_mtc ()) {
4146 /* mark us ready to send */
4147 next_quarter_frame_to_send = 0;
4150 } else if (p == "send-mmc") {
4152 _mmc->enable_send (Config->get_send_mmc ());
4153 if (Config->get_send_mmc ()) {
4154 /* re-initialize MMC */
4155 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4156 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4159 } else if (p == "jack-time-master") {
4161 engine().reset_timebase ();
4163 } else if (p == "native-file-header-format") {
4165 if (!first_file_header_format_reset) {
4166 reset_native_file_format ();
4169 first_file_header_format_reset = false;
4171 } else if (p == "native-file-data-format") {
4173 if (!first_file_data_format_reset) {
4174 reset_native_file_format ();
4177 first_file_data_format_reset = false;
4179 } else if (p == "external-sync") {
4180 if (!config.get_external_sync()) {
4181 drop_sync_source ();
4183 switch_to_sync_source (Config->get_sync_source());
4185 } else if (p == "denormal-model") {
4187 } else if (p == "history-depth") {
4188 set_history_depth (Config->get_history_depth());
4189 } else if (p == "remote-model") {
4190 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4193 } else if (p == "initial-program-change") {
4195 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4198 buf[0] = MIDI::program; // channel zero by default
4199 buf[1] = (Config->get_initial_program_change() & 0x7f);
4201 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4203 } else if (p == "solo-mute-override") {
4204 // catch_up_on_solo_mute_override ();
4205 } else if (p == "listen-position" || p == "pfl-position") {
4206 listen_position_changed ();
4207 } else if (p == "solo-control-is-listen-control") {
4208 solo_control_mode_changed ();
4209 } else if (p == "solo-mute-gain") {
4210 _solo_cut_control->Changed (true, Controllable::NoGroup);
4211 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4212 last_timecode_valid = false;
4213 } else if (p == "playback-buffer-seconds") {
4214 AudioSource::allocate_working_buffers (sample_rate());
4215 } else if (p == "ltc-source-port") {
4216 reconnect_ltc_input ();
4217 } else if (p == "ltc-sink-port") {
4218 reconnect_ltc_output ();
4219 } else if (p == "timecode-generator-offset") {
4220 ltc_tx_parse_offset();
4221 } else if (p == "auto-return-target-list") {
4222 follow_playhead_priority ();
4229 Session::set_history_depth (uint32_t d)
4231 _history.set_depth (d);
4234 /** Connect things to the MMC object */
4236 Session::setup_midi_machine_control ()
4238 _mmc = new MIDI::MachineControl;
4240 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4241 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4243 if (!async_out || !async_out) {
4247 /* XXXX argh, passing raw pointers back into libmidi++ */
4249 MIDI::Port* mmc_in = async_in.get();
4250 MIDI::Port* mmc_out = async_out.get();
4252 _mmc->set_ports (mmc_in, mmc_out);
4254 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4255 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4256 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4257 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4258 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4259 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4260 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4261 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4262 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4263 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4264 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4265 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4266 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4268 /* also handle MIDI SPP because its so common */
4270 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4271 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4272 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4275 boost::shared_ptr<Controllable>
4276 Session::solo_cut_control() const
4278 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4279 * controls in Ardour that currently get presented to the user in the GUI that require
4280 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4282 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4283 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4286 return _solo_cut_control;
4290 Session::save_snapshot_name (const std::string & n)
4292 /* assure Stateful::_instant_xml is loaded
4293 * add_instant_xml() only adds to existing data and defaults
4294 * to use an empty Tree otherwise
4296 instant_xml ("LastUsedSnapshot");
4298 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4299 last_used_snapshot->set_property ("name", n);
4300 add_instant_xml (*last_used_snapshot, false);
4304 Session::set_snapshot_name (const std::string & n)
4306 _current_snapshot_name = n;
4307 save_snapshot_name (n);
4311 Session::rename (const std::string& new_name)
4313 string legal_name = legalize_for_path (new_name);
4319 string const old_sources_root = _session_dir->sources_root();
4321 if (!_writable || (_state_of_the_state & CannotSave)) {
4322 error << _("Cannot rename read-only session.") << endmsg;
4323 return 0; // don't show "messed up" warning
4325 if (record_status() == Recording) {
4326 error << _("Cannot rename session while recording") << endmsg;
4327 return 0; // don't show "messed up" warning
4330 StateProtector stp (this);
4335 * interchange subdirectory
4339 * Backup files are left unchanged and not renamed.
4342 /* Windows requires that we close all files before attempting the
4343 * rename. This works on other platforms, but isn't necessary there.
4344 * Leave it in place for all platforms though, since it may help
4345 * catch issues that could arise if the way Source files work ever
4346 * change (since most developers are not using Windows).
4349 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4350 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4356 /* pass one: not 100% safe check that the new directory names don't
4360 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4364 /* this is a stupid hack because Glib::path_get_dirname() is
4365 * lexical-only, and so passing it /a/b/c/ gives a different
4366 * result than passing it /a/b/c ...
4369 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4370 oldstr = oldstr.substr (0, oldstr.length() - 1);
4373 string base = Glib::path_get_dirname (oldstr);
4375 newstr = Glib::build_filename (base, legal_name);
4377 cerr << "Looking for " << newstr << endl;
4379 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4380 cerr << " exists\n";
4389 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4395 /* this is a stupid hack because Glib::path_get_dirname() is
4396 * lexical-only, and so passing it /a/b/c/ gives a different
4397 * result than passing it /a/b/c ...
4400 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4401 oldstr = oldstr.substr (0, oldstr.length() - 1);
4404 string base = Glib::path_get_dirname (oldstr);
4405 newstr = Glib::build_filename (base, legal_name);
4407 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4409 cerr << "Rename " << oldstr << " => " << newstr << endl;
4410 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4411 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4412 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4416 /* Reset path in "session dirs" */
4421 /* reset primary SessionDirectory object */
4424 (*_session_dir) = newstr;
4429 /* now rename directory below session_dir/interchange */
4431 string old_interchange_dir;
4432 string new_interchange_dir;
4434 /* use newstr here because we renamed the path
4435 * (folder/directory) that used to be oldstr to newstr above
4438 v.push_back (newstr);
4439 v.push_back (interchange_dir_name);
4440 v.push_back (Glib::path_get_basename (oldstr));
4442 old_interchange_dir = Glib::build_filename (v);
4445 v.push_back (newstr);
4446 v.push_back (interchange_dir_name);
4447 v.push_back (legal_name);
4449 new_interchange_dir = Glib::build_filename (v);
4451 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4453 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4454 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4455 old_interchange_dir, new_interchange_dir,
4458 error << string_compose (_("renaming %s as %2 failed (%3)"),
4459 old_interchange_dir, new_interchange_dir,
4468 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4469 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4471 cerr << "Rename " << oldstr << " => " << newstr << endl;
4473 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4474 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4475 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4481 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4483 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4484 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4486 cerr << "Rename " << oldstr << " => " << newstr << endl;
4488 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4489 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4490 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4495 /* remove old name from recent sessions */
4496 remove_recent_sessions (_path);
4499 /* update file source paths */
4501 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4502 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4504 string p = fs->path ();
4505 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4507 SourceFactory::setup_peakfile(i->second, true);
4511 set_snapshot_name (new_name);
4516 /* save state again to get everything just right */
4518 save_state (_current_snapshot_name);
4520 /* add to recent sessions */
4522 store_recent_sessions (new_name, _path);
4528 Session::parse_stateful_loading_version (const std::string& version)
4530 if (version.empty ()) {
4531 /* no version implies very old version of Ardour */
4535 if (version.find ('.') != string::npos) {
4536 /* old school version format */
4537 if (version[0] == '2') {
4543 return string_to<int32_t>(version);
4548 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4550 bool found_sr = false;
4551 bool found_data_format = false;
4552 std::string version;
4553 program_version = "";
4555 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4559 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4563 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4566 xmlFreeParserCtxt(ctxt);
4570 xmlNodePtr node = xmlDocGetRootElement(doc);
4573 xmlFreeParserCtxt(ctxt);
4578 /* sample rate & version*/
4581 for (attr = node->properties; attr; attr = attr->next) {
4582 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4583 version = std::string ((char*)attr->children->content);
4585 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4586 sample_rate = atoi ((char*)attr->children->content);
4591 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4595 node = node->children;
4596 while (node != NULL) {
4597 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4598 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4600 program_version = string ((const char*)val);
4601 size_t sep = program_version.find_first_of("-");
4602 if (sep != string::npos) {
4603 program_version = program_version.substr (0, sep);
4608 if (strcmp((const char*) node->name, "Config")) {
4612 for (node = node->children; node; node = node->next) {
4613 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4614 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4616 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4619 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4621 found_data_format = true;
4622 } catch (PBD::unknown_enumeration& e) {}
4632 xmlFreeParserCtxt(ctxt);
4635 return (found_sr && found_data_format) ? 0 : 1;
4639 Session::get_snapshot_from_instant (const std::string& session_dir)
4641 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4643 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4648 if (!tree.read (instant_xml_path)) {
4652 XMLProperty const * prop;
4653 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4654 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4655 return prop->value();
4661 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4662 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4665 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4669 SourcePathMap source_path_map;
4671 boost::shared_ptr<AudioFileSource> afs;
4676 Glib::Threads::Mutex::Lock lm (source_lock);
4678 cerr << " total sources = " << sources.size();
4680 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4681 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4687 if (fs->within_session()) {
4691 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4692 source_path_map[fs->path()].push_back (fs);
4694 SeveralFileSources v;
4696 source_path_map.insert (make_pair (fs->path(), v));
4702 cerr << " fsources = " << total << endl;
4704 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4706 /* tell caller where we are */
4708 string old_path = i->first;
4710 callback (n, total, old_path);
4712 cerr << old_path << endl;
4716 switch (i->second.front()->type()) {
4717 case DataType::AUDIO:
4718 new_path = new_audio_source_path_for_embedded (old_path);
4721 case DataType::MIDI:
4722 /* XXX not implemented yet */
4726 if (new_path.empty()) {
4730 cerr << "Move " << old_path << " => " << new_path << endl;
4732 if (!copy_file (old_path, new_path)) {
4733 cerr << "failed !\n";
4737 /* make sure we stop looking in the external
4738 dir/folder. Remember, this is an all-or-nothing
4739 operations, it doesn't merge just some files.
4741 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4743 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4744 (*f)->set_path (new_path);
4749 save_state ("", false, false);
4755 bool accept_all_files (string const &, void *)
4761 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4763 /* 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.
4768 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4770 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4772 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4774 v.push_back (new_session_folder); /* full path */
4775 v.push_back (interchange_dir_name);
4776 v.push_back (new_session_path); /* just one directory/folder */
4777 v.push_back (typedir);
4778 v.push_back (Glib::path_get_basename (old_path));
4780 return Glib::build_filename (v);
4784 Session::save_as (SaveAs& saveas)
4786 vector<string> files;
4787 string current_folder = Glib::path_get_dirname (_path);
4788 string new_folder = legalize_for_path (saveas.new_name);
4789 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4790 int64_t total_bytes = 0;
4794 int32_t internal_file_cnt = 0;
4796 vector<string> do_not_copy_extensions;
4797 do_not_copy_extensions.push_back (statefile_suffix);
4798 do_not_copy_extensions.push_back (pending_suffix);
4799 do_not_copy_extensions.push_back (backup_suffix);
4800 do_not_copy_extensions.push_back (temp_suffix);
4801 do_not_copy_extensions.push_back (history_suffix);
4803 /* get total size */
4805 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4807 /* need to clear this because
4808 * find_files_matching_filter() is cumulative
4813 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4815 all += files.size();
4817 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4819 g_stat ((*i).c_str(), &gsb);
4820 total_bytes += gsb.st_size;
4824 /* save old values so we can switch back if we are not switching to the new session */
4826 string old_path = _path;
4827 string old_name = _name;
4828 string old_snapshot = _current_snapshot_name;
4829 string old_sd = _session_dir->root_path();
4830 vector<string> old_search_path[DataType::num_types];
4831 string old_config_search_path[DataType::num_types];
4833 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4834 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4835 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4836 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4838 /* switch session directory */
4840 (*_session_dir) = to_dir;
4842 /* create new tree */
4844 if (!_session_dir->create()) {
4845 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4850 /* copy all relevant files. Find each location in session_dirs,
4851 * and copy files from there to target.
4854 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4856 /* need to clear this because
4857 * find_files_matching_filter() is cumulative
4862 const size_t prefix_len = (*sd).path.size();
4864 /* Work just on the files within this session dir */
4866 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4868 /* add dir separator to protect against collisions with
4869 * track names (e.g. track named "audiofiles" or
4873 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4874 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4875 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4877 /* copy all the files. Handling is different for media files
4878 than others because of the *silly* subtree we have below the interchange
4879 folder. That really was a bad idea, but I'm not fixing it as part of
4880 implementing ::save_as().
4883 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4885 std::string from = *i;
4888 string filename = Glib::path_get_basename (from);
4889 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4890 if (filename == ".DS_STORE") {
4895 if (from.find (audiofile_dir_string) != string::npos) {
4897 /* audio file: only copy if asked */
4899 if (saveas.include_media && saveas.copy_media) {
4901 string to = make_new_media_path (*i, to_dir, new_folder);
4903 info << "media file copying from " << from << " to " << to << endmsg;
4905 if (!copy_file (from, to)) {
4906 throw Glib::FileError (Glib::FileError::IO_ERROR,
4907 string_compose(_("\ncopying \"%1\" failed !"), from));
4911 /* we found media files inside the session folder */
4913 internal_file_cnt++;
4915 } else if (from.find (midifile_dir_string) != string::npos) {
4917 /* midi file: always copy unless
4918 * creating an empty new session
4921 if (saveas.include_media) {
4923 string to = make_new_media_path (*i, to_dir, new_folder);
4925 info << "media file copying from " << from << " to " << to << endmsg;
4927 if (!copy_file (from, to)) {
4928 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4932 /* we found media files inside the session folder */
4934 internal_file_cnt++;
4936 } else if (from.find (analysis_dir_string) != string::npos) {
4938 /* make sure analysis dir exists in
4939 * new session folder, but we're not
4940 * copying analysis files here, see
4944 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4949 /* normal non-media file. Don't copy state, history, etc.
4952 bool do_copy = true;
4954 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4955 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4956 /* end of filename matches extension, do not copy file */
4962 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4963 /* don't copy peakfiles if
4964 * we're not copying media
4970 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4972 info << "attempting to make directory/folder " << to << endmsg;
4974 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4975 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4978 info << "attempting to copy " << from << " to " << to << endmsg;
4980 if (!copy_file (from, to)) {
4981 throw Glib::FileError (Glib::FileError::IO_ERROR,
4982 string_compose(_("\ncopying \"%1\" failed !"), from));
4987 /* measure file size even if we're not going to copy so that our Progress
4988 signals are correct, since we included these do-not-copy files
4989 in the computation of the total size and file count.
4993 g_stat (from.c_str(), &gsb);
4994 copied += gsb.st_size;
4997 double fraction = (double) copied / total_bytes;
4999 bool keep_going = true;
5001 if (saveas.copy_media) {
5003 /* no need or expectation of this if
5004 * media is not being copied, because
5005 * it will be fast(ish).
5008 /* tell someone "X percent, file M of N"; M is one-based */
5010 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5018 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5024 /* copy optional folders, if any */
5026 string old = plugins_dir ();
5027 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5028 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5029 copy_files (old, newdir);
5032 old = externals_dir ();
5033 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5034 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5035 copy_files (old, newdir);
5038 old = automation_dir ();
5039 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5040 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5041 copy_files (old, newdir);
5044 if (saveas.include_media) {
5046 if (saveas.copy_media) {
5047 #ifndef PLATFORM_WINDOWS
5048 /* There are problems with analysis files on
5049 * Windows, because they used a colon in their
5050 * names as late as 4.0. Colons are not legal
5051 * under Windows even if NTFS allows them.
5053 * This is a tricky problem to solve so for
5054 * just don't copy these files. They will be
5055 * regenerated as-needed anyway, subject to the
5056 * existing issue that the filenames will be
5057 * rejected by Windows, which is a separate
5058 * problem (though related).
5061 /* only needed if we are copying media, since the
5062 * analysis data refers to media data
5065 old = analysis_dir ();
5066 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5067 string newdir = Glib::build_filename (to_dir, "analysis");
5068 copy_files (old, newdir);
5070 #endif /* PLATFORM_WINDOWS */
5075 set_snapshot_name (saveas.new_name);
5076 _name = saveas.new_name;
5078 if (saveas.include_media && !saveas.copy_media) {
5080 /* reset search paths of the new session (which we're pretending to be right now) to
5081 include the original session search path, so we can still find all audio.
5084 if (internal_file_cnt) {
5085 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5086 ensure_search_path_includes (*s, DataType::AUDIO);
5087 cerr << "be sure to include " << *s << " for audio" << endl;
5090 /* we do not do this for MIDI because we copy
5091 all MIDI files if saveas.include_media is
5097 bool was_dirty = dirty ();
5099 save_default_options ();
5101 if (saveas.copy_media && saveas.copy_external) {
5102 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5103 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5107 saveas.final_session_folder_name = _path;
5109 store_recent_sessions (_name, _path);
5111 if (!saveas.switch_to) {
5113 /* save the new state */
5115 save_state ("", false, false, !saveas.include_media);
5117 /* switch back to the way things were */
5121 set_snapshot_name (old_snapshot);
5123 (*_session_dir) = old_sd;
5129 if (internal_file_cnt) {
5130 /* reset these to their original values */
5131 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5132 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5137 /* prune session dirs, and update disk space statistics
5142 session_dirs.clear ();
5143 session_dirs.push_back (sp);
5144 refresh_disk_space ();
5146 _writable = exists_and_writable (_path);
5148 /* ensure that all existing tracks reset their current capture source paths
5150 reset_write_sources (true, true);
5152 /* creating new write sources marks the session as
5153 dirty. If the new session is empty, then
5154 save_state() thinks we're saving a template and will
5155 not mark the session as clean. So do that here,
5156 before we save state.
5159 if (!saveas.include_media) {
5160 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5163 save_state ("", false, false, !saveas.include_media);
5165 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5166 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5169 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5170 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5176 if (fs->within_session()) {
5177 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5178 fs->set_path (newpath);
5183 } catch (Glib::FileError& e) {
5185 saveas.failure_message = e.what();
5187 /* recursively remove all the directories */
5189 remove_directory (to_dir);
5197 saveas.failure_message = _("unknown reason");
5199 /* recursively remove all the directories */
5201 remove_directory (to_dir);
5211 static void set_progress (Progress* p, size_t n, size_t t)
5213 p->set_progress (float (n) / float(t));
5217 Session::archive_session (const std::string& dest,
5218 const std::string& name,
5219 ArchiveEncode compress_audio,
5220 FileArchive::CompressionLevel compression_level,
5221 bool only_used_sources,
5224 if (dest.empty () || name.empty ()) {
5228 /* save current values */
5229 bool was_dirty = dirty ();
5230 string old_path = _path;
5231 string old_name = _name;
5232 string old_snapshot = _current_snapshot_name;
5233 string old_sd = _session_dir->root_path();
5234 string old_config_search_path[DataType::num_types];
5235 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5236 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5238 /* ensure that session-path is included in search-path */
5240 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5241 if ((*sd).path == old_path) {
5249 /* create temporary dir to save session to */
5250 #ifdef PLATFORM_WINDOWS
5251 char tmp[256] = "C:\\TEMP\\";
5252 GetTempPath (sizeof (tmp), tmp);
5254 char const* tmp = getenv("TMPDIR");
5259 if ((strlen (tmp) + 21) > 1024) {
5264 strcpy (tmptpl, tmp);
5265 strcat (tmptpl, "ardourarchive-XXXXXX");
5266 char* tmpdir = g_mkdtemp (tmptpl);
5272 std::string to_dir = std::string (tmpdir);
5274 /* switch session directory temporarily */
5275 (*_session_dir) = to_dir;
5277 if (!_session_dir->create()) {
5278 (*_session_dir) = old_sd;
5279 remove_directory (to_dir);
5283 /* prepare archive */
5284 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5286 PBD::ScopedConnectionList progress_connection;
5287 PBD::FileArchive ar (archive);
5289 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5292 /* collect files to archive */
5293 std::map<string,string> filemap;
5295 vector<string> do_not_copy_extensions;
5296 do_not_copy_extensions.push_back (statefile_suffix);
5297 do_not_copy_extensions.push_back (pending_suffix);
5298 do_not_copy_extensions.push_back (backup_suffix);
5299 do_not_copy_extensions.push_back (temp_suffix);
5300 do_not_copy_extensions.push_back (history_suffix);
5302 vector<string> blacklist_dirs;
5303 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5304 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5305 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5306 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5307 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5308 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5310 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5311 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5313 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5314 if (only_used_sources) {
5315 playlists->sync_all_regions_with_regions ();
5316 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5319 // collect audio sources for this session, calc total size for encoding
5320 // add option to only include *used* sources (see Session::cleanup_sources)
5321 size_t total_size = 0;
5323 Glib::Threads::Mutex::Lock lm (source_lock);
5324 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5325 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5326 if (!afs || afs->readable_length () == 0) {
5330 if (only_used_sources) {
5334 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5339 std::string from = afs->path();
5341 if (compress_audio != NO_ENCODE) {
5342 total_size += afs->readable_length ();
5344 if (afs->within_session()) {
5345 filemap[from] = make_new_media_path (from, name, name);
5347 filemap[from] = make_new_media_path (from, name, name);
5348 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5355 if (compress_audio != NO_ENCODE) {
5357 progress->set_progress (2); // set to "encoding"
5358 progress->set_progress (0);
5361 Glib::Threads::Mutex::Lock lm (source_lock);
5362 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5363 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5364 if (!afs || afs->readable_length () == 0) {
5368 if (only_used_sources) {
5372 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5377 orig_sources[afs] = afs->path();
5378 orig_gain[afs] = afs->gain();
5380 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5382 std::string channelsuffix = "";
5383 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5384 /* embedded external multi-channel files are converted to multiple-mono */
5385 channelsuffix = string_compose ("-c%1", afs->channel ());
5387 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5388 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5392 progress->descend ((float)afs->readable_length () / total_size);
5396 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5397 afs->replace_file (new_path);
5398 afs->set_gain (ns->gain(), true);
5401 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5405 progress->ascend ();
5411 progress->set_progress (-1); // set to "archiving"
5412 progress->set_progress (0);
5415 /* index files relevant for this session */
5416 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5417 vector<string> files;
5419 size_t prefix_len = (*sd).path.size();
5420 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5424 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5426 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5427 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5428 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5430 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5431 std::string from = *i;
5434 string filename = Glib::path_get_basename (from);
5435 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5436 if (filename == ".DS_STORE") {
5441 if (from.find (audiofile_dir_string) != string::npos) {
5443 } else if (from.find (midifile_dir_string) != string::npos) {
5444 filemap[from] = make_new_media_path (from, name, name);
5445 } else if (from.find (videofile_dir_string) != string::npos) {
5446 filemap[from] = make_new_media_path (from, name, name);
5448 bool do_copy = true;
5449 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5450 if (from.find (*v) != string::npos) {
5455 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5456 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5463 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5469 /* write session file */
5471 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5473 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5475 save_state (name, /*pending, don't fork MIDI, don't mark clean */ true);
5478 cerr << "archiving state from "
5479 << Glib::build_filename (to_dir, legalize_for_path (name) + pending_suffix)
5481 << Glib::build_filename (to_dir, legalize_for_path (name) + statefile_suffix)
5486 Glib::build_filename (to_dir, legalize_for_path (name) + pending_suffix).c_str(),
5487 Glib::build_filename (to_dir, legalize_for_path (name) + statefile_suffix).c_str());
5489 save_default_options ();
5491 size_t prefix_len = _path.size();
5492 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5496 /* collect session-state files */
5497 vector<string> files;
5498 do_not_copy_extensions.clear ();
5499 do_not_copy_extensions.push_back (history_suffix);
5501 blacklist_dirs.clear ();
5502 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5504 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5505 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5506 std::string from = *i;
5507 bool do_copy = true;
5508 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5509 if (from.find (*v) != string::npos) {
5514 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5515 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5521 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5525 /* restore original values */
5528 set_snapshot_name (old_snapshot);
5529 (*_session_dir) = old_sd;
5533 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5534 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5536 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5537 i->first->replace_file (i->second);
5539 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5540 i->first->set_gain (i->second, true);
5543 int rv = ar.create (filemap, compression_level);
5544 remove_directory (to_dir);
5550 Session::undo (uint32_t n)
5552 if (actively_recording()) {
5560 Session::redo (uint32_t n)
5562 if (actively_recording()) {