2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/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_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/sndfilesource.h"
124 #include "ardour/source_factory.h"
125 #include "ardour/speakers.h"
126 #include "ardour/template_utils.h"
127 #include "ardour/tempo.h"
128 #include "ardour/ticker.h"
129 #include "ardour/types_convert.h"
130 #include "ardour/user_bundle.h"
131 #include "ardour/vca.h"
132 #include "ardour/vca_manager.h"
134 #include "control_protocol/control_protocol.h"
136 #include "LuaBridge/LuaBridge.h"
138 #include "pbd/i18n.h"
142 using namespace ARDOUR;
145 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
148 Session::pre_engine_init (string fullpath)
150 if (fullpath.empty()) {
152 throw failed_constructor();
155 /* discover canonical fullpath */
157 _path = canonical_path(fullpath);
160 if (Profile->get_trx() ) {
161 // Waves TracksLive has a usecase of session replacement with a new one.
162 // We should check session state file (<session_name>.ardour) existance
163 // to determine if the session is new or not
165 string full_session_name = Glib::build_filename( fullpath, _name );
166 full_session_name += statefile_suffix;
168 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 /* finish initialization that can't be done in a normal C++ constructor
177 timerclear (&last_mmc_step);
178 g_atomic_int_set (&processing_prohibited, 0);
179 g_atomic_int_set (&_record_status, Disabled);
180 g_atomic_int_set (&_playback_load, 100);
181 g_atomic_int_set (&_capture_load, 100);
183 _all_route_group->set_active (true, this);
184 interpolation.add_channel_to (0, 0);
186 if (config.get_use_video_sync()) {
187 waiting_for_sync_offset = true;
189 waiting_for_sync_offset = false;
192 last_rr_session_dir = session_dirs.begin();
194 set_history_depth (Config->get_history_depth());
196 /* default: assume simple stereo speaker configuration */
198 _speakers->setup_default_speakers (2);
200 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
201 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
202 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
203 add_controllable (_solo_cut_control);
205 /* These are all static "per-class" signals */
207 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
208 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
209 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
210 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
213 /* stop IO objects from doing stuff until we're ready for them */
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
220 Session::post_engine_init ()
222 BootMessage (_("Set block size and sample rate"));
224 set_block_size (_engine.samples_per_cycle());
225 set_frame_rate (_engine.sample_rate());
227 BootMessage (_("Using configuration"));
229 _midi_ports = new MidiPortManager;
231 MIDISceneChanger* msc;
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
237 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
240 setup_midi_machine_control ();
242 if (_butler->start_thread()) {
243 error << _("Butler did not start") << endmsg;
247 if (start_midi_thread ()) {
248 error << _("MIDI I/O thread did not start") << endmsg;
252 setup_click_sounds (0);
253 setup_midi_control ();
255 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
256 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
259 /* tempo map requires sample rate knowledge */
262 _tempo_map = new TempoMap (_current_frame_rate);
263 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
264 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 /* MidiClock requires a tempo map */
269 midi_clock = new MidiClockTicker ();
270 midi_clock->set_session (this);
272 /* crossfades require sample rate knowledge */
274 SndFileSource::setup_standard_crossfades (*this, frame_rate());
275 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
276 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
278 AudioDiskstream::allocate_working_buffers();
279 refresh_disk_space ();
281 /* we're finally ready to call set_state() ... all objects have
282 * been created, the engine is running.
286 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
287 error << _("Could not set session state from XML") << endmsg;
291 // set_state() will call setup_raid_path(), but if it's a new session we need
292 // to call setup_raid_path() here.
293 setup_raid_path (_path);
298 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
299 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
301 Config->map_parameters (ff);
302 config.map_parameters (ft);
303 _butler->map_parameters ();
305 /* Reset all panners */
307 Delivery::reset_panners ();
309 /* this will cause the CPM to instantiate any protocols that are in use
310 * (or mandatory), which will pass it this Session, and then call
311 * set_state() on each instantiated protocol to match stored state.
314 ControlProtocolManager::instance().set_session (this);
316 /* This must be done after the ControlProtocolManager set_session above,
317 as it will set states for ports which the ControlProtocolManager creates.
320 // XXX set state of MIDI::Port's
321 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
323 /* And this must be done after the MIDI::Manager::set_port_states as
324 * it will try to make connections whose details are loaded by set_port_states.
329 /* Let control protocols know that we are now all connected, so they
330 * could start talking to surfaces if they want to.
333 ControlProtocolManager::instance().midi_connectivity_established ();
335 if (_is_new && !no_auto_connect()) {
336 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
337 auto_connect_master_bus ();
340 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
342 /* update latencies */
344 initialize_latencies ();
346 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
347 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
348 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
350 } catch (AudioEngine::PortRegistrationFailure& err) {
351 /* handle this one in a different way than all others, so that its clear what happened */
352 error << err.what() << endmsg;
354 } catch (std::exception const & e) {
355 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
358 error << _("Unknown exception during session setup") << endmsg;
362 BootMessage (_("Reset Remote Controls"));
364 // send_full_time_code (0);
365 _engine.transport_locate (0);
367 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
368 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
370 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
373 /* initial program change will be delivered later; see ::config_changed() */
375 _state_of_the_state = Clean;
377 Port::set_connecting_blocked (false);
379 DirtyChanged (); /* EMIT SIGNAL */
383 } else if (state_was_pending) {
385 remove_pending_capture_state ();
386 state_was_pending = false;
389 /* Now, finally, we can fill the playback buffers */
391 BootMessage (_("Filling playback buffers"));
393 boost::shared_ptr<RouteList> rl = routes.reader();
394 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
395 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
396 if (trk && !trk->hidden()) {
397 trk->seek (_transport_frame, true);
405 Session::session_loaded ()
409 _state_of_the_state = Clean;
411 DirtyChanged (); /* EMIT SIGNAL */
415 } else if (state_was_pending) {
417 remove_pending_capture_state ();
418 state_was_pending = false;
421 /* Now, finally, we can fill the playback buffers */
423 BootMessage (_("Filling playback buffers"));
424 force_locate (_transport_frame, false);
428 Session::raid_path () const
430 Searchpath raid_search_path;
432 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
433 raid_search_path += (*i).path;
436 return raid_search_path.to_string ();
440 Session::setup_raid_path (string path)
449 session_dirs.clear ();
451 Searchpath search_path(path);
452 Searchpath sound_search_path;
453 Searchpath midi_search_path;
455 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
457 sp.blocks = 0; // not needed
458 session_dirs.push_back (sp);
460 SessionDirectory sdir(sp.path);
462 sound_search_path += sdir.sound_path ();
463 midi_search_path += sdir.midi_path ();
466 // reset the round-robin soundfile path thingie
467 last_rr_session_dir = session_dirs.begin();
471 Session::path_is_within_session (const std::string& path)
473 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
474 if (PBD::path_is_within (i->path, path)) {
482 Session::ensure_subdirs ()
486 dir = session_directory().peak_path();
488 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
489 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
493 dir = session_directory().sound_path();
495 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
496 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
500 dir = session_directory().midi_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = session_directory().dead_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().export_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = analysis_dir ();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = plugins_dir ();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 dir = externals_dir ();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
545 /** @param session_template directory containing session template, or empty.
546 * Caller must not hold process lock.
549 Session::create (const string& session_template, BusProfile* bus_profile)
551 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
556 if (ensure_subdirs ()) {
560 _writable = exists_and_writable (_path);
562 if (!session_template.empty()) {
563 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
565 FILE* in = g_fopen (in_path.c_str(), "rb");
568 /* no need to call legalize_for_path() since the string
569 * in session_template is already a legal path name
571 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
573 FILE* out = g_fopen (out_path.c_str(), "wb");
577 stringstream new_session;
580 size_t charsRead = fread (buf, sizeof(char), 1024, in);
583 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
588 if (charsRead == 0) {
591 new_session.write (buf, charsRead);
595 string file_contents = new_session.str();
596 size_t writeSize = file_contents.length();
597 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
598 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
606 if (!ARDOUR::Profile->get_trx()) {
607 /* Copy plugin state files from template to new session */
608 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
609 copy_recurse (template_plugins, plugins_dir ());
615 error << string_compose (_("Could not open %1 for writing session template"), out_path)
622 error << string_compose (_("Could not open session template %1 for reading"), in_path)
629 if (Profile->get_trx()) {
631 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
632 Remember that this is a brand new session. Sessions
633 loaded from saved state will get this range from the saved state.
636 set_session_range_location (0, 0);
638 /* Initial loop location, from absolute zero, length 10 seconds */
640 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
641 _locations->add (loc, true);
642 set_auto_loop_location (loc);
645 _state_of_the_state = Clean;
647 /* set up Master Out and Monitor Out if necessary */
652 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
654 // Waves Tracks: always create master bus for Tracks
655 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
656 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
664 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
665 r->input()->ensure_io (count, false, this);
666 r->output()->ensure_io (count, false, this);
672 /* prohibit auto-connect to master, because there isn't one */
673 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
677 add_routes (rl, false, false, false, PresentationInfo::max_order);
680 // Waves Tracks: Skip this. Always use autoconnection for Tracks
681 if (!ARDOUR::Profile->get_trx()) {
683 /* this allows the user to override settings with an environment variable.
686 if (no_auto_connect()) {
687 bus_profile->input_ac = AutoConnectOption (0);
688 bus_profile->output_ac = AutoConnectOption (0);
691 Config->set_input_auto_connect (bus_profile->input_ac);
692 Config->set_output_auto_connect (bus_profile->output_ac);
696 if (Config->get_use_monitor_bus() && bus_profile) {
697 add_monitor_section ();
704 Session::maybe_write_autosave()
706 if (dirty() && record_status() != Recording) {
707 save_state("", true);
712 Session::remove_pending_capture_state ()
714 std::string pending_state_file_path(_session_dir->root_path());
716 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
718 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
720 if (g_remove (pending_state_file_path.c_str()) != 0) {
721 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
722 pending_state_file_path, g_strerror (errno)) << endmsg;
726 /** Rename a state file.
727 * @param old_name Old snapshot name.
728 * @param new_name New snapshot name.
731 Session::rename_state (string old_name, string new_name)
733 if (old_name == _current_snapshot_name || old_name == _name) {
734 /* refuse to rename the current snapshot or the "main" one */
738 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
739 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
741 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
742 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
744 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
745 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
746 old_name, new_name, g_strerror(errno)) << endmsg;
750 /** Remove a state file.
751 * @param snapshot_name Snapshot name.
754 Session::remove_state (string snapshot_name)
756 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
757 // refuse to remove the current snapshot or the "main" one
761 std::string xml_path(_session_dir->root_path());
763 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
765 if (!create_backup_file (xml_path)) {
766 // don't remove it if a backup can't be made
767 // create_backup_file will log the error.
772 if (g_remove (xml_path.c_str()) != 0) {
773 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
774 xml_path, g_strerror (errno)) << endmsg;
778 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
780 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
782 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
785 std::string xml_path(_session_dir->root_path());
787 /* prevent concurrent saves from different threads */
789 Glib::Threads::Mutex::Lock lm (save_state_lock);
791 if (!_writable || (_state_of_the_state & CannotSave)) {
795 if (g_atomic_int_get(&_suspend_save)) {
799 _save_queued = false;
801 if (!_engine.connected ()) {
802 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
809 const int64_t save_start_time = g_get_monotonic_time();
812 /* tell sources we're saving first, in case they write out to a new file
813 * which should be saved with the state rather than the old one */
814 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
816 i->second->session_saved();
817 } catch (Evoral::SMF::FileError& e) {
818 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
822 SessionSaveUnderway (); /* EMIT SIGNAL */
824 bool mark_as_clean = true;
826 if (!snapshot_name.empty() && !switch_to_snapshot) {
827 mark_as_clean = false;
831 mark_as_clean = false;
832 tree.set_root (&get_template());
834 tree.set_root (&get_state());
837 if (snapshot_name.empty()) {
838 snapshot_name = _current_snapshot_name;
839 } else if (switch_to_snapshot) {
840 set_snapshot_name (snapshot_name);
843 assert (!snapshot_name.empty());
847 /* proper save: use statefile_suffix (.ardour in English) */
849 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
851 /* make a backup copy of the old file */
853 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
854 // create_backup_file will log the error
860 /* pending save: use pending_suffix (.pending in English) */
861 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
864 std::string tmp_path(_session_dir->root_path());
865 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
867 cerr << "actually writing state to " << tmp_path << endl;
869 if (!tree.write (tmp_path)) {
870 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
871 if (g_remove (tmp_path.c_str()) != 0) {
872 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
873 tmp_path, g_strerror (errno)) << endmsg;
879 cerr << "renaming state to " << xml_path << endl;
881 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
882 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
883 tmp_path, xml_path, g_strerror(errno)) << endmsg;
884 if (g_remove (tmp_path.c_str()) != 0) {
885 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
886 tmp_path, g_strerror (errno)) << endmsg;
894 save_history (snapshot_name);
897 bool was_dirty = dirty();
899 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
902 DirtyChanged (); /* EMIT SIGNAL */
906 StateSaved (snapshot_name); /* EMIT SIGNAL */
910 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
911 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
917 Session::restore_state (string snapshot_name)
919 if (load_state (snapshot_name) == 0) {
920 set_state (*state_tree->root(), Stateful::loading_state_version);
927 Session::load_state (string snapshot_name)
932 state_was_pending = false;
934 /* check for leftover pending state from a crashed capture attempt */
936 std::string xmlpath(_session_dir->root_path());
937 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
939 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
941 /* there is pending state from a crashed capture attempt */
943 boost::optional<int> r = AskAboutPendingState();
944 if (r.get_value_or (1)) {
945 state_was_pending = true;
949 if (!state_was_pending) {
950 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
953 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
954 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
955 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
956 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
961 state_tree = new XMLTree;
965 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
967 if (!state_tree->read (xmlpath)) {
968 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
974 XMLNode const & root (*state_tree->root());
976 if (root.name() != X_("Session")) {
977 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
984 if (root.get_property ("version", version)) {
985 if (version.find ('.') != string::npos) {
986 /* old school version format */
987 if (version[0] == '2') {
988 Stateful::loading_state_version = 2000;
990 Stateful::loading_state_version = 3000;
993 Stateful::loading_state_version = string_to<int32_t>(version);
996 /* no version implies very old version of Ardour */
997 Stateful::loading_state_version = 1000;
1000 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1002 std::string backup_path(_session_dir->root_path());
1003 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1004 backup_path = Glib::build_filename (backup_path, backup_filename);
1006 // only create a backup for a given statefile version once
1008 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1010 VersionMismatch (xmlpath, backup_path);
1012 if (!copy_file (xmlpath, backup_path)) {;
1018 save_snapshot_name (snapshot_name);
1024 Session::load_options (const XMLNode& node)
1027 config.set_variables (node);
1032 Session::save_default_options ()
1034 return config.save_state();
1038 Session::get_state()
1044 Session::get_template()
1046 /* if we don't disable rec-enable, diskstreams
1047 will believe they need to store their capture
1048 sources in their state node.
1051 disable_record (false);
1053 return state(false);
1056 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1057 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1060 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1062 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1065 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1069 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1072 XMLNode* node = new XMLNode("TrackState"); // XXX
1075 PlaylistSet playlists; // SessionPlaylists
1078 // these will work with new_route_from_template()
1079 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1080 child = node->add_child ("Routes");
1081 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1082 if ((*i)->is_auditioner()) {
1085 if ((*i)->is_master() || (*i)->is_monitor()) {
1088 child->add_child_nocopy ((*i)->get_state());
1089 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1091 playlists.insert (track->playlist ());
1095 // on load, Regions in the playlists need to resolve and map Source-IDs
1096 // also playlist needs to be merged or created with new-name..
1097 // ... and Diskstream in tracks adjusted to use the correct playlist
1098 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1099 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1100 child->add_child_nocopy ((*i)->get_state ());
1101 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1102 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1103 const Region::SourceList& sl = (*s)->sources ();
1104 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1105 sources.insert (*sli);
1110 child = node->add_child ("Sources");
1111 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1112 child->add_child_nocopy ((*i)->get_state ());
1113 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1115 #ifdef PLATFORM_WINDOWS
1118 string p = fs->path ();
1119 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1123 std::string sn = Glib::build_filename (path, "share.axml");
1126 tree.set_root (node);
1127 return tree.write (sn.c_str());
1131 Session::state (bool full_state)
1134 XMLNode* node = new XMLNode("Session");
1137 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1139 child = node->add_child ("ProgramVersion");
1140 child->set_property("created-with", created_with);
1142 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1143 child->set_property("modified-with", modified_with);
1145 /* store configuration settings */
1149 node->set_property ("name", _name);
1150 node->set_property ("sample-rate", _base_frame_rate);
1152 if (session_dirs.size() > 1) {
1156 vector<space_and_path>::iterator i = session_dirs.begin();
1157 vector<space_and_path>::iterator next;
1159 ++i; /* skip the first one */
1163 while (i != session_dirs.end()) {
1167 if (next != session_dirs.end()) {
1168 p += G_SEARCHPATH_SEPARATOR;
1177 child = node->add_child ("Path");
1178 child->add_content (p);
1182 node->set_property ("end-is-free", _session_range_end_is_free);
1184 /* save the ID counter */
1186 node->set_property ("id-counter", ID::counter());
1188 node->set_property ("name-counter", name_id_counter ());
1190 /* save the event ID counter */
1192 node->set_property ("event-counter", Evoral::event_id_counter());
1194 /* save the VCA counter */
1196 node->set_property ("vca-counter", VCA::get_next_vca_number());
1198 /* various options */
1200 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1201 if (!midi_port_nodes.empty()) {
1202 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1203 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1204 midi_port_stuff->add_child_nocopy (**n);
1206 node->add_child_nocopy (*midi_port_stuff);
1209 XMLNode& cfgxml (config.get_variables ());
1211 /* exclude search-paths from template */
1212 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1213 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1214 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1216 node->add_child_nocopy (cfgxml);
1218 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1220 child = node->add_child ("Sources");
1223 Glib::Threads::Mutex::Lock sl (source_lock);
1225 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1227 /* Don't save information about non-file Sources, or
1228 * about non-destructive file sources that are empty
1229 * and unused by any regions.
1232 boost::shared_ptr<FileSource> fs;
1234 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1236 if (!fs->destructive()) {
1237 if (fs->empty() && !fs->used()) {
1242 child->add_child_nocopy (siter->second->get_state());
1247 child = node->add_child ("Regions");
1250 Glib::Threads::Mutex::Lock rl (region_lock);
1251 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1252 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1253 boost::shared_ptr<Region> r = i->second;
1254 /* only store regions not attached to playlists */
1255 if (r->playlist() == 0) {
1256 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1257 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1259 child->add_child_nocopy (r->get_state ());
1264 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1266 if (!cassocs.empty()) {
1267 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1269 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1270 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1271 can->set_property (X_("copy"), i->first->id());
1272 can->set_property (X_("original"), i->second->id());
1273 ca->add_child_nocopy (*can);
1283 node->add_child_nocopy (_locations->get_state());
1286 Locations loc (*this);
1287 const bool was_dirty = dirty();
1288 // for a template, just create a new Locations, populate it
1289 // with the default start and end, and get the state for that.
1290 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1291 range->set (max_framepos, 0);
1293 XMLNode& locations_state = loc.get_state();
1295 if (ARDOUR::Profile->get_trx() && _locations) {
1296 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1297 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1298 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1299 locations_state.add_child_nocopy ((*i)->get_state ());
1303 node->add_child_nocopy (locations_state);
1305 /* adding a location above will have marked the session
1306 * dirty. This is an artifact, so fix it if the session wasn't
1311 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1315 child = node->add_child ("Bundles");
1317 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1318 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1319 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1321 child->add_child_nocopy (b->get_state());
1326 node->add_child_nocopy (_vca_manager->get_state());
1328 child = node->add_child ("Routes");
1330 boost::shared_ptr<RouteList> r = routes.reader ();
1332 RoutePublicOrderSorter cmp;
1333 RouteList public_order (*r);
1334 public_order.sort (cmp);
1336 /* the sort should have put the monitor out first */
1339 assert (_monitor_out == public_order.front());
1342 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1343 if (!(*i)->is_auditioner()) {
1345 child->add_child_nocopy ((*i)->get_state());
1347 child->add_child_nocopy ((*i)->get_template());
1353 playlists->add_state (node, full_state);
1355 child = node->add_child ("RouteGroups");
1356 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1357 child->add_child_nocopy ((*i)->get_state());
1361 XMLNode* gain_child = node->add_child ("Click");
1362 gain_child->add_child_nocopy (_click_io->state (full_state));
1363 gain_child->add_child_nocopy (_click_gain->state (full_state));
1367 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1368 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1372 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1373 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1376 node->add_child_nocopy (_speakers->get_state());
1377 node->add_child_nocopy (_tempo_map->get_state());
1378 node->add_child_nocopy (get_control_protocol_state());
1381 node->add_child_copy (*_extra_xml);
1385 Glib::Threads::Mutex::Lock lm (lua_lock);
1388 luabridge::LuaRef savedstate ((*_lua_save)());
1389 saved = savedstate.cast<std::string>();
1391 lua.collect_garbage ();
1394 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1395 std::string b64s (b64);
1398 XMLNode* script_node = new XMLNode (X_("Script"));
1399 script_node->set_property (X_("lua"), LUA_VERSION);
1400 script_node->add_content (b64s);
1401 node->add_child_nocopy (*script_node);
1408 Session::get_control_protocol_state ()
1410 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1411 return cpm.get_state();
1415 Session::set_state (const XMLNode& node, int version)
1422 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1424 if (node.name() != X_("Session")) {
1425 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1429 node.get_property ("name", _name);
1431 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1433 _nominal_frame_rate = _base_frame_rate;
1435 assert (AudioEngine::instance()->running ());
1436 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1437 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1438 if (r.get_value_or (0)) {
1444 created_with = "unknown";
1445 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1446 child->get_property (X_("created-with"), created_with);
1449 setup_raid_path(_session_dir->root_path());
1451 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1454 if (node.get_property (X_("id-counter"), counter)) {
1455 ID::init_counter (counter);
1457 /* old sessions used a timebased counter, so fake
1458 the startup ID counter based on a standard
1463 ID::init_counter (now);
1466 if (node.get_property (X_("name-counter"), counter)) {
1467 init_name_id_counter (counter);
1470 if (node.get_property (X_("event-counter"), counter)) {
1471 Evoral::init_event_id_counter (counter);
1474 if (node.get_property (X_("vca-counter"), counter)) {
1475 VCA::set_next_vca_number (counter);
1477 VCA::set_next_vca_number (1);
1480 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1481 _midi_ports->set_midi_port_states (child->children());
1484 IO::disable_connecting ();
1486 Stateful::save_extra_xml (node);
1488 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1489 load_options (*child);
1490 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1491 load_options (*child);
1493 error << _("Session: XML state has no options section") << endmsg;
1496 if (version >= 3000) {
1497 if ((child = find_named_node (node, "Metadata")) == 0) {
1498 warning << _("Session: XML state has no metadata section") << endmsg;
1499 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1504 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1505 _speakers->set_state (*child, version);
1508 if ((child = find_named_node (node, "Sources")) == 0) {
1509 error << _("Session: XML state has no sources section") << endmsg;
1511 } else if (load_sources (*child)) {
1515 if ((child = find_named_node (node, "TempoMap")) == 0) {
1516 error << _("Session: XML state has no Tempo Map section") << endmsg;
1518 } else if (_tempo_map->set_state (*child, version)) {
1522 if ((child = find_named_node (node, "Locations")) == 0) {
1523 error << _("Session: XML state has no locations section") << endmsg;
1525 } else if (_locations->set_state (*child, version)) {
1529 locations_changed ();
1531 if (_session_range_location) {
1532 AudioFileSource::set_header_position_offset (_session_range_location->start());
1535 if ((child = find_named_node (node, "Regions")) == 0) {
1536 error << _("Session: XML state has no Regions section") << endmsg;
1538 } else if (load_regions (*child)) {
1542 if ((child = find_named_node (node, "Playlists")) == 0) {
1543 error << _("Session: XML state has no playlists section") << endmsg;
1545 } else if (playlists->load (*this, *child)) {
1549 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1551 } else if (playlists->load_unused (*this, *child)) {
1555 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1556 if (load_compounds (*child)) {
1561 if (version >= 3000) {
1562 if ((child = find_named_node (node, "Bundles")) == 0) {
1563 warning << _("Session: XML state has no bundles section") << endmsg;
1566 /* We can't load Bundles yet as they need to be able
1567 to convert from port names to Port objects, which can't happen until
1569 _bundle_xml_node = new XMLNode (*child);
1573 if (version < 3000) {
1574 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1575 error << _("Session: XML state has no diskstreams section") << endmsg;
1577 } else if (load_diskstreams_2X (*child, version)) {
1582 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1583 _vca_manager->set_state (*child, version);
1586 if ((child = find_named_node (node, "Routes")) == 0) {
1587 error << _("Session: XML state has no routes section") << endmsg;
1589 } else if (load_routes (*child, version)) {
1593 /* Now that we have Routes and masters loaded, connect them if appropriate */
1595 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1597 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1598 _diskstreams_2X.clear ();
1600 if (version >= 3000) {
1602 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1603 error << _("Session: XML state has no route groups section") << endmsg;
1605 } else if (load_route_groups (*child, version)) {
1609 } else if (version < 3000) {
1611 if ((child = find_named_node (node, "EditGroups")) == 0) {
1612 error << _("Session: XML state has no edit groups section") << endmsg;
1614 } else if (load_route_groups (*child, version)) {
1618 if ((child = find_named_node (node, "MixGroups")) == 0) {
1619 error << _("Session: XML state has no mix groups section") << endmsg;
1621 } else if (load_route_groups (*child, version)) {
1626 if ((child = find_named_node (node, "Click")) == 0) {
1627 warning << _("Session: XML state has no click section") << endmsg;
1628 } else if (_click_io) {
1629 setup_click_state (&node);
1632 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1633 ControlProtocolManager::instance().set_state (*child, version);
1636 if ((child = find_named_node (node, "Script"))) {
1637 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1638 if (!(*n)->is_content ()) { continue; }
1640 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1642 Glib::Threads::Mutex::Lock lm (lua_lock);
1643 (*_lua_load)(std::string ((const char*)buf, size));
1644 } catch (luabridge::LuaException const& e) {
1645 cerr << "LuaException:" << e.what () << endl;
1651 update_route_record_state ();
1653 /* here beginneth the second phase ... */
1654 set_snapshot_name (_current_snapshot_name);
1656 StateReady (); /* EMIT SIGNAL */
1669 Session::load_routes (const XMLNode& node, int version)
1672 XMLNodeConstIterator niter;
1673 RouteList new_routes;
1675 nlist = node.children();
1679 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1681 boost::shared_ptr<Route> route;
1682 if (version < 3000) {
1683 route = XMLRouteFactory_2X (**niter, version);
1685 route = XMLRouteFactory (**niter, version);
1689 error << _("Session: cannot create Route from XML description.") << endmsg;
1693 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1695 new_routes.push_back (route);
1698 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1700 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1702 BootMessage (_("Finished adding tracks/busses"));
1707 boost::shared_ptr<Route>
1708 Session::XMLRouteFactory (const XMLNode& node, int version)
1710 boost::shared_ptr<Route> ret;
1712 if (node.name() != "Route") {
1716 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1718 DataType type = DataType::AUDIO;
1719 node.get_property("default-type", type);
1721 assert (type != DataType::NIL);
1725 boost::shared_ptr<Track> track;
1727 if (type == DataType::AUDIO) {
1728 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1730 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1733 if (track->init()) {
1737 if (track->set_state (node, version)) {
1741 BOOST_MARK_TRACK (track);
1745 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1746 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1748 if (r->init () == 0 && r->set_state (node, version) == 0) {
1749 BOOST_MARK_ROUTE (r);
1757 boost::shared_ptr<Route>
1758 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1760 boost::shared_ptr<Route> ret;
1762 if (node.name() != "Route") {
1766 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1768 ds_prop = node.property (X_("diskstream"));
1771 DataType type = DataType::AUDIO;
1772 node.get_property("default-type", type);
1774 assert (type != DataType::NIL);
1778 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1779 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1783 if (i == _diskstreams_2X.end()) {
1784 error << _("Could not find diskstream for route") << endmsg;
1785 return boost::shared_ptr<Route> ();
1788 boost::shared_ptr<Track> track;
1790 if (type == DataType::AUDIO) {
1791 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1793 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1796 if (track->init()) {
1800 if (track->set_state (node, version)) {
1804 track->set_diskstream (*i);
1806 BOOST_MARK_TRACK (track);
1810 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1811 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1813 if (r->init () == 0 && r->set_state (node, version) == 0) {
1814 BOOST_MARK_ROUTE (r);
1823 Session::load_regions (const XMLNode& node)
1826 XMLNodeConstIterator niter;
1827 boost::shared_ptr<Region> region;
1829 nlist = node.children();
1833 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1834 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1835 error << _("Session: cannot create Region from XML description.");
1836 XMLProperty const * name = (**niter).property("name");
1839 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1850 Session::load_compounds (const XMLNode& node)
1852 XMLNodeList calist = node.children();
1853 XMLNodeConstIterator caiter;
1854 XMLProperty const * caprop;
1856 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1857 XMLNode* ca = *caiter;
1861 if ((caprop = ca->property (X_("original"))) == 0) {
1864 orig_id = caprop->value();
1866 if ((caprop = ca->property (X_("copy"))) == 0) {
1869 copy_id = caprop->value();
1871 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1872 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1874 if (!orig || !copy) {
1875 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1881 RegionFactory::add_compound_association (orig, copy);
1888 Session::load_nested_sources (const XMLNode& node)
1891 XMLNodeConstIterator niter;
1893 nlist = node.children();
1895 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1896 if ((*niter)->name() == "Source") {
1898 /* it may already exist, so don't recreate it unnecessarily
1901 XMLProperty const * prop = (*niter)->property (X_("id"));
1903 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1907 ID source_id (prop->value());
1909 if (!source_by_id (source_id)) {
1912 SourceFactory::create (*this, **niter, true);
1914 catch (failed_constructor& err) {
1915 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1922 boost::shared_ptr<Region>
1923 Session::XMLRegionFactory (const XMLNode& node, bool full)
1925 XMLProperty const * type = node.property("type");
1929 const XMLNodeList& nlist = node.children();
1931 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1932 XMLNode *child = (*niter);
1933 if (child->name() == "NestedSource") {
1934 load_nested_sources (*child);
1938 if (!type || type->value() == "audio") {
1939 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1940 } else if (type->value() == "midi") {
1941 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1944 } catch (failed_constructor& err) {
1945 return boost::shared_ptr<Region> ();
1948 return boost::shared_ptr<Region> ();
1951 boost::shared_ptr<AudioRegion>
1952 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1954 XMLProperty const * prop;
1955 boost::shared_ptr<Source> source;
1956 boost::shared_ptr<AudioSource> as;
1958 SourceList master_sources;
1959 uint32_t nchans = 1;
1962 if (node.name() != X_("Region")) {
1963 return boost::shared_ptr<AudioRegion>();
1966 node.get_property (X_("channels"), nchans);
1968 if ((prop = node.property ("name")) == 0) {
1969 cerr << "no name for this region\n";
1973 if ((prop = node.property (X_("source-0"))) == 0) {
1974 if ((prop = node.property ("source")) == 0) {
1975 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1976 return boost::shared_ptr<AudioRegion>();
1980 PBD::ID s_id (prop->value());
1982 if ((source = source_by_id (s_id)) == 0) {
1983 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1984 return boost::shared_ptr<AudioRegion>();
1987 as = boost::dynamic_pointer_cast<AudioSource>(source);
1989 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1990 return boost::shared_ptr<AudioRegion>();
1993 sources.push_back (as);
1995 /* pickup other channels */
1997 for (uint32_t n=1; n < nchans; ++n) {
1998 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1999 if ((prop = node.property (buf)) != 0) {
2001 PBD::ID id2 (prop->value());
2003 if ((source = source_by_id (id2)) == 0) {
2004 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2005 return boost::shared_ptr<AudioRegion>();
2008 as = boost::dynamic_pointer_cast<AudioSource>(source);
2010 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2011 return boost::shared_ptr<AudioRegion>();
2013 sources.push_back (as);
2017 for (uint32_t n = 0; n < nchans; ++n) {
2018 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2019 if ((prop = node.property (buf)) != 0) {
2021 PBD::ID id2 (prop->value());
2023 if ((source = source_by_id (id2)) == 0) {
2024 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2025 return boost::shared_ptr<AudioRegion>();
2028 as = boost::dynamic_pointer_cast<AudioSource>(source);
2030 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2031 return boost::shared_ptr<AudioRegion>();
2033 master_sources.push_back (as);
2038 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2040 /* a final detail: this is the one and only place that we know how long missing files are */
2042 if (region->whole_file()) {
2043 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2044 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2046 sfp->set_length (region->length());
2051 if (!master_sources.empty()) {
2052 if (master_sources.size() != nchans) {
2053 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2055 region->set_master_sources (master_sources);
2063 catch (failed_constructor& err) {
2064 return boost::shared_ptr<AudioRegion>();
2068 boost::shared_ptr<MidiRegion>
2069 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2071 XMLProperty const * prop;
2072 boost::shared_ptr<Source> source;
2073 boost::shared_ptr<MidiSource> ms;
2076 if (node.name() != X_("Region")) {
2077 return boost::shared_ptr<MidiRegion>();
2080 if ((prop = node.property ("name")) == 0) {
2081 cerr << "no name for this region\n";
2085 if ((prop = node.property (X_("source-0"))) == 0) {
2086 if ((prop = node.property ("source")) == 0) {
2087 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2088 return boost::shared_ptr<MidiRegion>();
2092 PBD::ID s_id (prop->value());
2094 if ((source = source_by_id (s_id)) == 0) {
2095 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2096 return boost::shared_ptr<MidiRegion>();
2099 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2101 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2102 return boost::shared_ptr<MidiRegion>();
2105 sources.push_back (ms);
2108 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2109 /* a final detail: this is the one and only place that we know how long missing files are */
2111 if (region->whole_file()) {
2112 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2113 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2115 sfp->set_length (region->length());
2123 catch (failed_constructor& err) {
2124 return boost::shared_ptr<MidiRegion>();
2129 Session::get_sources_as_xml ()
2132 XMLNode* node = new XMLNode (X_("Sources"));
2133 Glib::Threads::Mutex::Lock lm (source_lock);
2135 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2136 node->add_child_nocopy (i->second->get_state());
2143 Session::reset_write_sources (bool mark_write_complete, bool force)
2145 boost::shared_ptr<RouteList> rl = routes.reader();
2146 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2147 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2149 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2150 tr->reset_write_sources(mark_write_complete, force);
2151 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2157 Session::load_sources (const XMLNode& node)
2160 XMLNodeConstIterator niter;
2161 /* don't need this but it stops some
2162 * versions of gcc complaining about
2163 * discarded return values.
2165 boost::shared_ptr<Source> source;
2167 nlist = node.children();
2170 std::map<std::string, std::string> relocation;
2172 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2173 #ifdef PLATFORM_WINDOWS
2177 XMLNode srcnode (**niter);
2178 bool try_replace_abspath = true;
2182 #ifdef PLATFORM_WINDOWS
2183 // do not show "insert media" popups (files embedded from removable media).
2184 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2186 if ((source = XMLSourceFactory (srcnode)) == 0) {
2187 error << _("Session: cannot create Source from XML description.") << endmsg;
2189 #ifdef PLATFORM_WINDOWS
2190 SetErrorMode(old_mode);
2193 } catch (MissingSource& err) {
2194 #ifdef PLATFORM_WINDOWS
2195 SetErrorMode(old_mode);
2198 /* try previous abs path replacements first */
2199 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2200 std::string dir = Glib::path_get_dirname (err.path);
2201 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2202 if (rl != relocation.end ()) {
2203 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2204 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2205 srcnode.set_property ("origin", newpath);
2206 try_replace_abspath = false;
2213 _missing_file_replacement = "";
2215 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2216 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2217 PROGRAM_NAME) << endmsg;
2221 if (!no_questions_about_missing_files) {
2222 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2227 switch (user_choice) {
2229 /* user added a new search location
2230 * or selected a new absolute path,
2232 if (Glib::path_is_absolute (err.path)) {
2233 if (!_missing_file_replacement.empty ()) {
2234 /* replace origin, in XML */
2235 std::string newpath = Glib::build_filename (
2236 _missing_file_replacement, Glib::path_get_basename (err.path));
2237 srcnode.set_property ("origin", newpath);
2238 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2239 _missing_file_replacement = "";
2246 /* user asked to quit the entire session load */
2250 no_questions_about_missing_files = true;
2254 no_questions_about_missing_files = true;
2261 case DataType::AUDIO:
2262 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2265 case DataType::MIDI:
2266 /* The MIDI file is actually missing so
2267 * just create a new one in the same
2268 * location. Do not announce its
2272 if (!Glib::path_is_absolute (err.path)) {
2273 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2275 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2280 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2281 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2282 /* reset ID to match the missing one */
2283 source->set_id (**niter);
2284 /* Now we can announce it */
2285 SourceFactory::SourceCreated (source);
2296 boost::shared_ptr<Source>
2297 Session::XMLSourceFactory (const XMLNode& node)
2299 if (node.name() != "Source") {
2300 return boost::shared_ptr<Source>();
2304 /* note: do peak building in another thread when loading session state */
2305 return SourceFactory::create (*this, node, true);
2308 catch (failed_constructor& err) {
2309 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2310 return boost::shared_ptr<Source>();
2315 Session::save_template (string template_name, bool replace_existing)
2317 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2321 bool absolute_path = Glib::path_is_absolute (template_name);
2323 /* directory to put the template in */
2324 std::string template_dir_path;
2326 if (!absolute_path) {
2327 std::string user_template_dir(user_template_directory());
2329 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2330 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2331 user_template_dir, g_strerror (errno)) << endmsg;
2335 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2337 template_dir_path = template_name;
2340 if (!ARDOUR::Profile->get_trx()) {
2341 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2342 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2343 template_dir_path) << endmsg;
2347 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2348 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2349 template_dir_path, g_strerror (errno)) << endmsg;
2355 std::string template_file_path;
2357 if (ARDOUR::Profile->get_trx()) {
2358 template_file_path = template_name;
2360 if (absolute_path) {
2361 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2363 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2367 SessionSaveUnderway (); /* EMIT SIGNAL */
2372 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2373 tree.set_root (&get_template());
2376 if (!tree.write (template_file_path)) {
2377 error << _("template not saved") << endmsg;
2381 store_recent_templates (template_file_path);
2387 Session::refresh_disk_space ()
2389 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2391 Glib::Threads::Mutex::Lock lm (space_lock);
2393 /* get freespace on every FS that is part of the session path */
2395 _total_free_4k_blocks = 0;
2396 _total_free_4k_blocks_uncertain = false;
2398 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2399 #if defined(__NetBSD__)
2400 struct statvfs statfsbuf;
2402 statvfs (i->path.c_str(), &statfsbuf);
2404 struct statfs statfsbuf;
2406 statfs (i->path.c_str(), &statfsbuf);
2408 double const scale = statfsbuf.f_bsize / 4096.0;
2410 /* See if this filesystem is read-only */
2411 struct statvfs statvfsbuf;
2412 statvfs (i->path.c_str(), &statvfsbuf);
2414 /* f_bavail can be 0 if it is undefined for whatever
2415 filesystem we are looking at; Samba shares mounted
2416 via GVFS are an example of this.
2418 if (statfsbuf.f_bavail == 0) {
2419 /* block count unknown */
2421 i->blocks_unknown = true;
2422 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2423 /* read-only filesystem */
2425 i->blocks_unknown = false;
2427 /* read/write filesystem with known space */
2428 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2429 i->blocks_unknown = false;
2432 _total_free_4k_blocks += i->blocks;
2433 if (i->blocks_unknown) {
2434 _total_free_4k_blocks_uncertain = true;
2437 #elif defined PLATFORM_WINDOWS
2438 vector<string> scanned_volumes;
2439 vector<string>::iterator j;
2440 vector<space_and_path>::iterator i;
2441 DWORD nSectorsPerCluster, nBytesPerSector,
2442 nFreeClusters, nTotalClusters;
2446 _total_free_4k_blocks = 0;
2448 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2449 strncpy (disk_drive, (*i).path.c_str(), 3);
2453 volume_found = false;
2454 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2456 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2457 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2458 i->blocks = (uint32_t)(nFreeBytes / 4096);
2460 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2461 if (0 == j->compare(disk_drive)) {
2462 volume_found = true;
2467 if (!volume_found) {
2468 scanned_volumes.push_back(disk_drive);
2469 _total_free_4k_blocks += i->blocks;
2474 if (0 == _total_free_4k_blocks) {
2475 strncpy (disk_drive, path().c_str(), 3);
2478 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2480 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2481 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2482 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2489 Session::get_best_session_directory_for_new_audio ()
2491 vector<space_and_path>::iterator i;
2492 string result = _session_dir->root_path();
2494 /* handle common case without system calls */
2496 if (session_dirs.size() == 1) {
2500 /* OK, here's the algorithm we're following here:
2502 We want to select which directory to use for
2503 the next file source to be created. Ideally,
2504 we'd like to use a round-robin process so as to
2505 get maximum performance benefits from splitting
2506 the files across multiple disks.
2508 However, in situations without much diskspace, an
2509 RR approach may end up filling up a filesystem
2510 with new files while others still have space.
2511 Its therefore important to pay some attention to
2512 the freespace in the filesystem holding each
2513 directory as well. However, if we did that by
2514 itself, we'd keep creating new files in the file
2515 system with the most space until it was as full
2516 as all others, thus negating any performance
2517 benefits of this RAID-1 like approach.
2519 So, we use a user-configurable space threshold. If
2520 there are at least 2 filesystems with more than this
2521 much space available, we use RR selection between them.
2522 If not, then we pick the filesystem with the most space.
2524 This gets a good balance between the two
2528 refresh_disk_space ();
2530 int free_enough = 0;
2532 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2533 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2538 if (free_enough >= 2) {
2539 /* use RR selection process, ensuring that the one
2543 i = last_rr_session_dir;
2546 if (++i == session_dirs.end()) {
2547 i = session_dirs.begin();
2550 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2551 SessionDirectory sdir(i->path);
2552 if (sdir.create ()) {
2554 last_rr_session_dir = i;
2559 } while (i != last_rr_session_dir);
2563 /* pick FS with the most freespace (and that
2564 seems to actually work ...)
2567 vector<space_and_path> sorted;
2568 space_and_path_ascending_cmp cmp;
2570 sorted = session_dirs;
2571 sort (sorted.begin(), sorted.end(), cmp);
2573 for (i = sorted.begin(); i != sorted.end(); ++i) {
2574 SessionDirectory sdir(i->path);
2575 if (sdir.create ()) {
2577 last_rr_session_dir = i;
2587 Session::automation_dir () const
2589 return Glib::build_filename (_path, automation_dir_name);
2593 Session::analysis_dir () const
2595 return Glib::build_filename (_path, analysis_dir_name);
2599 Session::plugins_dir () const
2601 return Glib::build_filename (_path, plugins_dir_name);
2605 Session::externals_dir () const
2607 return Glib::build_filename (_path, externals_dir_name);
2611 Session::load_bundles (XMLNode const & node)
2613 XMLNodeList nlist = node.children();
2614 XMLNodeConstIterator niter;
2618 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2619 if ((*niter)->name() == "InputBundle") {
2620 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2621 } else if ((*niter)->name() == "OutputBundle") {
2622 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2624 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2633 Session::load_route_groups (const XMLNode& node, int version)
2635 XMLNodeList nlist = node.children();
2636 XMLNodeConstIterator niter;
2640 if (version >= 3000) {
2642 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2643 if ((*niter)->name() == "RouteGroup") {
2644 RouteGroup* rg = new RouteGroup (*this, "");
2645 add_route_group (rg);
2646 rg->set_state (**niter, version);
2650 } else if (version < 3000) {
2652 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2653 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2654 RouteGroup* rg = new RouteGroup (*this, "");
2655 add_route_group (rg);
2656 rg->set_state (**niter, version);
2665 state_file_filter (const string &str, void* /*arg*/)
2667 return (str.length() > strlen(statefile_suffix) &&
2668 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2672 remove_end(string state)
2674 string statename(state);
2676 string::size_type start,end;
2677 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2678 statename = statename.substr (start+1);
2681 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2682 end = statename.length();
2685 return string(statename.substr (0, end));
2689 Session::possible_states (string path)
2691 vector<string> states;
2692 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2694 transform(states.begin(), states.end(), states.begin(), remove_end);
2696 sort (states.begin(), states.end());
2702 Session::possible_states () const
2704 return possible_states(_path);
2708 Session::new_route_group (const std::string& name)
2710 RouteGroup* rg = NULL;
2712 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2713 if ((*i)->name () == name) {
2720 rg = new RouteGroup (*this, name);
2721 add_route_group (rg);
2727 Session::add_route_group (RouteGroup* g)
2729 _route_groups.push_back (g);
2730 route_group_added (g); /* EMIT SIGNAL */
2732 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2733 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2734 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2740 Session::remove_route_group (RouteGroup& rg)
2742 list<RouteGroup*>::iterator i;
2744 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2745 _route_groups.erase (i);
2748 route_group_removed (); /* EMIT SIGNAL */
2752 /** Set a new order for our route groups, without adding or removing any.
2753 * @param groups Route group list in the new order.
2756 Session::reorder_route_groups (list<RouteGroup*> groups)
2758 _route_groups = groups;
2760 route_groups_reordered (); /* EMIT SIGNAL */
2766 Session::route_group_by_name (string name)
2768 list<RouteGroup *>::iterator i;
2770 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2771 if ((*i)->name() == name) {
2779 Session::all_route_group() const
2781 return *_all_route_group;
2785 Session::add_commands (vector<Command*> const & cmds)
2787 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2793 Session::add_command (Command* const cmd)
2795 assert (_current_trans);
2796 DEBUG_UNDO_HISTORY (
2797 string_compose ("Current Undo Transaction %1, adding command: %2",
2798 _current_trans->name (),
2800 _current_trans->add_command (cmd);
2803 PBD::StatefulDiffCommand*
2804 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2806 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2812 Session::begin_reversible_command (const string& name)
2814 begin_reversible_command (g_quark_from_string (name.c_str ()));
2817 /** Begin a reversible command using a GQuark to identify it.
2818 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2819 * but there must be as many begin...()s as there are commit...()s.
2822 Session::begin_reversible_command (GQuark q)
2824 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2825 to hold all the commands that are committed. This keeps the order of
2826 commands correct in the history.
2829 if (_current_trans == 0) {
2830 DEBUG_UNDO_HISTORY (string_compose (
2831 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2833 /* start a new transaction */
2834 assert (_current_trans_quarks.empty ());
2835 _current_trans = new UndoTransaction();
2836 _current_trans->set_name (g_quark_to_string (q));
2838 DEBUG_UNDO_HISTORY (
2839 string_compose ("Begin Reversible Command, current transaction: %1",
2840 _current_trans->name ()));
2843 _current_trans_quarks.push_front (q);
2847 Session::abort_reversible_command ()
2849 if (_current_trans != 0) {
2850 DEBUG_UNDO_HISTORY (
2851 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2852 _current_trans->clear();
2853 delete _current_trans;
2855 _current_trans_quarks.clear();
2860 Session::commit_reversible_command (Command *cmd)
2862 assert (_current_trans);
2863 assert (!_current_trans_quarks.empty ());
2868 DEBUG_UNDO_HISTORY (
2869 string_compose ("Current Undo Transaction %1, adding command: %2",
2870 _current_trans->name (),
2872 _current_trans->add_command (cmd);
2875 DEBUG_UNDO_HISTORY (
2876 string_compose ("Commit Reversible Command, current transaction: %1",
2877 _current_trans->name ()));
2879 _current_trans_quarks.pop_front ();
2881 if (!_current_trans_quarks.empty ()) {
2882 DEBUG_UNDO_HISTORY (
2883 string_compose ("Commit Reversible Command, transaction is not "
2884 "top-level, current transaction: %1",
2885 _current_trans->name ()));
2886 /* the transaction we're committing is not the top-level one */
2890 if (_current_trans->empty()) {
2891 /* no commands were added to the transaction, so just get rid of it */
2892 DEBUG_UNDO_HISTORY (
2893 string_compose ("Commit Reversible Command, No commands were "
2894 "added to current transaction: %1",
2895 _current_trans->name ()));
2896 delete _current_trans;
2901 gettimeofday (&now, 0);
2902 _current_trans->set_timestamp (now);
2904 _history.add (_current_trans);
2909 accept_all_audio_files (const string& path, void* /*arg*/)
2911 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2915 if (!AudioFileSource::safe_audio_file_extension (path)) {
2923 accept_all_midi_files (const string& path, void* /*arg*/)
2925 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2929 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2930 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2931 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2935 accept_all_state_files (const string& path, void* /*arg*/)
2937 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2941 std::string const statefile_ext (statefile_suffix);
2942 if (path.length() >= statefile_ext.length()) {
2943 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2950 Session::find_all_sources (string path, set<string>& result)
2955 if (!tree.read (path)) {
2959 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2964 XMLNodeConstIterator niter;
2966 nlist = node->children();
2970 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2972 XMLProperty const * prop;
2974 if ((prop = (*niter)->property (X_("type"))) == 0) {
2978 DataType type (prop->value());
2980 if ((prop = (*niter)->property (X_("name"))) == 0) {
2984 if (Glib::path_is_absolute (prop->value())) {
2985 /* external file, ignore */
2993 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2994 result.insert (found_path);
3002 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3004 vector<string> state_files;
3006 string this_snapshot_path;
3012 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3013 ripped = ripped.substr (0, ripped.length() - 1);
3016 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3018 if (state_files.empty()) {
3023 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3024 this_snapshot_path += statefile_suffix;
3026 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3028 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3030 if (exclude_this_snapshot && *i == this_snapshot_path) {
3031 cerr << "\texcluded\n";
3036 if (find_all_sources (*i, result) < 0) {
3044 struct RegionCounter {
3045 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3046 AudioSourceList::iterator iter;
3047 boost::shared_ptr<Region> region;
3050 RegionCounter() : count (0) {}
3054 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3056 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3057 return r.get_value_or (1);
3061 Session::cleanup_regions ()
3063 bool removed = false;
3064 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3066 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3068 uint32_t used = playlists->region_use_count (i->second);
3070 if (used == 0 && !i->second->automatic ()) {
3071 boost::weak_ptr<Region> w = i->second;
3074 RegionFactory::map_remove (w);
3081 // re-check to remove parent references of compound regions
3082 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3083 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3087 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3088 if (0 == playlists->region_use_count (i->second)) {
3089 boost::weak_ptr<Region> w = i->second;
3091 RegionFactory::map_remove (w);
3098 /* dump the history list */
3105 Session::can_cleanup_peakfiles () const
3107 if (deletion_in_progress()) {
3110 if (!_writable || (_state_of_the_state & CannotSave)) {
3111 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3114 if (record_status() == Recording) {
3115 error << _("Cannot cleanup peak-files while recording") << endmsg;
3122 Session::cleanup_peakfiles ()
3124 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3129 assert (can_cleanup_peakfiles ());
3130 assert (!peaks_cleanup_in_progres());
3132 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3134 int timeout = 5000; // 5 seconds
3135 while (!SourceFactory::files_with_peaks.empty()) {
3136 Glib::usleep (1000);
3137 if (--timeout < 0) {
3138 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3139 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3144 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3145 boost::shared_ptr<AudioSource> as;
3146 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3147 as->close_peakfile();
3151 PBD::clear_directory (session_directory().peak_path());
3153 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3155 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3156 boost::shared_ptr<AudioSource> as;
3157 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3158 SourceFactory::setup_peakfile(as, true);
3165 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3167 pl->deep_sources (*all_sources);
3171 Session::cleanup_sources (CleanupReport& rep)
3173 // FIXME: needs adaptation to midi
3175 vector<boost::shared_ptr<Source> > dead_sources;
3178 vector<string> candidates;
3179 vector<string> unused;
3180 set<string> sources_used_by_all_snapshots;
3187 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3189 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3191 /* this is mostly for windows which doesn't allow file
3192 * renaming if the file is in use. But we don't special
3193 * case it because we need to know if this causes
3194 * problems, and the easiest way to notice that is to
3195 * keep it in place for all platforms.
3198 request_stop (false);
3200 _butler->wait_until_finished ();
3202 /* consider deleting all unused playlists */
3204 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3209 /* sync the "all regions" property of each playlist with its current state
3212 playlists->sync_all_regions_with_regions ();
3214 /* find all un-used sources */
3219 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3221 SourceMap::iterator tmp;
3226 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3230 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3231 dead_sources.push_back (i->second);
3232 i->second->drop_references ();
3238 /* build a list of all the possible audio directories for the session */
3240 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3241 SessionDirectory sdir ((*i).path);
3242 asp += sdir.sound_path();
3244 audio_path += asp.to_string();
3247 /* build a list of all the possible midi directories for the session */
3249 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3250 SessionDirectory sdir ((*i).path);
3251 msp += sdir.midi_path();
3253 midi_path += msp.to_string();
3255 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3256 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3258 /* add sources from all other snapshots as "used", but don't use this
3259 snapshot because the state file on disk still references sources we
3260 may have already dropped.
3263 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3265 /* Although the region factory has a list of all regions ever created
3266 * for this session, we're only interested in regions actually in
3267 * playlists right now. So merge all playlist regions lists together.
3269 * This will include the playlists used within compound regions.
3272 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3274 /* add our current source list
3277 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3278 boost::shared_ptr<FileSource> fs;
3279 SourceMap::iterator tmp = i;
3282 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3288 /* this is mostly for windows which doesn't allow file
3289 * renaming if the file is in use. But we do not special
3290 * case it because we need to know if this causes
3291 * problems, and the easiest way to notice that is to
3292 * keep it in place for all platforms.
3297 if (!fs->is_stub()) {
3299 /* Note that we're checking a list of all
3300 * sources across all snapshots with the list
3301 * of sources used by this snapshot.
3304 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3305 /* this source is in use by this snapshot */
3306 sources_used_by_all_snapshots.insert (fs->path());
3307 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3309 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3310 /* this source is NOT in use by this snapshot
3313 /* remove all related regions from RegionFactory master list
3316 RegionFactory::remove_regions_using_source (i->second);
3318 /* remove from our current source list
3319 * also. We may not remove it from
3320 * disk, because it may be used by
3321 * other snapshots, but it isn't used inside this
3322 * snapshot anymore, so we don't need a
3333 /* now check each candidate source to see if it exists in the list of
3334 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3337 cerr << "Candidates: " << candidates.size() << endl;
3338 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3340 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3345 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3347 tmppath1 = canonical_path (spath);
3348 tmppath2 = canonical_path ((*i));
3350 cerr << "\t => " << tmppath2 << endl;
3352 if (tmppath1 == tmppath2) {
3359 unused.push_back (spath);
3363 cerr << "Actually unused: " << unused.size() << endl;
3365 if (unused.empty()) {
3371 /* now try to move all unused files into the "dead" directory(ies) */
3373 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3378 /* don't move the file across filesystems, just
3379 stick it in the `dead_dir_name' directory
3380 on whichever filesystem it was already on.
3383 if ((*x).find ("/sounds/") != string::npos) {
3385 /* old school, go up 1 level */
3387 newpath = Glib::path_get_dirname (*x); // "sounds"
3388 newpath = Glib::path_get_dirname (newpath); // "session-name"
3392 /* new school, go up 4 levels */
3394 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3395 newpath = Glib::path_get_dirname (newpath); // "session-name"
3396 newpath = Glib::path_get_dirname (newpath); // "interchange"
3397 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3400 newpath = Glib::build_filename (newpath, dead_dir_name);
3402 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3403 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3407 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3409 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3411 /* the new path already exists, try versioning */
3413 char buf[PATH_MAX+1];
3417 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3420 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3421 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3425 if (version == 999) {
3426 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3430 newpath = newpath_v;
3435 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3436 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3437 newpath, g_strerror (errno)) << endmsg;
3441 /* see if there an easy to find peakfile for this file, and remove it.
3444 string base = Glib::path_get_basename (*x);
3445 base += "%A"; /* this is what we add for the channel suffix of all native files,
3446 or for the first channel of embedded files. it will miss
3447 some peakfiles for other channels
3449 string peakpath = construct_peak_filepath (base);
3451 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3452 if (::g_unlink (peakpath.c_str ()) != 0) {
3453 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3454 g_strerror (errno)) << endmsg;
3455 /* try to back out */
3456 ::g_rename (newpath.c_str (), _path.c_str ());
3461 rep.paths.push_back (*x);
3462 rep.space += statbuf.st_size;
3465 /* dump the history list */
3469 /* save state so we don't end up a session file
3470 referring to non-existent sources.
3477 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3483 Session::cleanup_trash_sources (CleanupReport& rep)
3485 // FIXME: needs adaptation for MIDI
3487 vector<space_and_path>::iterator i;
3493 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3495 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3497 clear_directory (dead_dir, &rep.space, &rep.paths);
3504 Session::set_dirty ()
3506 /* return early if there's nothing to do */
3511 /* never mark session dirty during loading */
3512 if (_state_of_the_state & Loading) {
3516 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3517 DirtyChanged(); /* EMIT SIGNAL */
3521 Session::set_clean ()
3523 bool was_dirty = dirty();
3525 _state_of_the_state = Clean;
3528 DirtyChanged(); /* EMIT SIGNAL */
3533 Session::set_deletion_in_progress ()
3535 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3539 Session::clear_deletion_in_progress ()
3541 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3545 Session::add_controllable (boost::shared_ptr<Controllable> c)
3547 /* this adds a controllable to the list managed by the Session.
3548 this is a subset of those managed by the Controllable class
3549 itself, and represents the only ones whose state will be saved
3550 as part of the session.
3553 Glib::Threads::Mutex::Lock lm (controllables_lock);
3554 controllables.insert (c);
3557 struct null_deleter { void operator()(void const *) const {} };
3560 Session::remove_controllable (Controllable* c)
3562 if (_state_of_the_state & Deletion) {
3566 Glib::Threads::Mutex::Lock lm (controllables_lock);
3568 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3570 if (x != controllables.end()) {
3571 controllables.erase (x);
3575 boost::shared_ptr<Controllable>
3576 Session::controllable_by_id (const PBD::ID& id)
3578 Glib::Threads::Mutex::Lock lm (controllables_lock);
3580 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3581 if ((*i)->id() == id) {
3586 return boost::shared_ptr<Controllable>();
3589 boost::shared_ptr<Controllable>
3590 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3592 boost::shared_ptr<Controllable> c;
3593 boost::shared_ptr<Stripable> s;
3594 boost::shared_ptr<Route> r;
3596 switch (desc.top_level_type()) {
3597 case ControllableDescriptor::NamedRoute:
3599 std::string str = desc.top_level_name();
3601 if (str == "Master" || str == "master") {
3603 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3605 } else if (str == "auditioner") {
3608 s = route_by_name (desc.top_level_name());
3614 case ControllableDescriptor::PresentationOrderRoute:
3615 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3618 case ControllableDescriptor::PresentationOrderTrack:
3619 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3622 case ControllableDescriptor::PresentationOrderBus:
3623 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3626 case ControllableDescriptor::PresentationOrderVCA:
3627 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3630 case ControllableDescriptor::SelectionCount:
3631 s = route_by_selected_count (desc.selection_id());
3639 r = boost::dynamic_pointer_cast<Route> (s);
3641 switch (desc.subtype()) {
3642 case ControllableDescriptor::Gain:
3643 c = s->gain_control ();
3646 case ControllableDescriptor::Trim:
3647 c = s->trim_control ();
3650 case ControllableDescriptor::Solo:
3651 c = s->solo_control();
3654 case ControllableDescriptor::Mute:
3655 c = s->mute_control();
3658 case ControllableDescriptor::Recenable:
3659 c = s->rec_enable_control ();
3662 case ControllableDescriptor::PanDirection:
3663 c = s->pan_azimuth_control();
3666 case ControllableDescriptor::PanWidth:
3667 c = s->pan_width_control();
3670 case ControllableDescriptor::PanElevation:
3671 c = s->pan_elevation_control();
3674 case ControllableDescriptor::Balance:
3675 /* XXX simple pan control */
3678 case ControllableDescriptor::PluginParameter:
3680 uint32_t plugin = desc.target (0);
3681 uint32_t parameter_index = desc.target (1);
3683 /* revert to zero based counting */
3689 if (parameter_index > 0) {
3697 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3700 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3701 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3706 case ControllableDescriptor::SendGain: {
3707 uint32_t send = desc.target (0);
3714 c = r->send_level_controllable (send);
3719 /* relax and return a null pointer */
3727 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3730 Stateful::add_instant_xml (node, _path);
3733 if (write_to_config) {
3734 Config->add_instant_xml (node);
3739 Session::instant_xml (const string& node_name)
3741 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3742 if (get_disable_all_loaded_plugins ()) {
3746 return Stateful::instant_xml (node_name, _path);
3750 Session::save_history (string snapshot_name)
3758 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3759 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3763 if (snapshot_name.empty()) {
3764 snapshot_name = _current_snapshot_name;
3767 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3768 const string backup_filename = history_filename + backup_suffix;
3769 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3770 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3772 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3773 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3774 error << _("could not backup old history file, current history not saved") << endmsg;
3779 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3781 if (!tree.write (xml_path))
3783 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3785 if (g_remove (xml_path.c_str()) != 0) {
3786 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3787 xml_path, g_strerror (errno)) << endmsg;
3789 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3790 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3791 backup_path, g_strerror (errno)) << endmsg;
3801 Session::restore_history (string snapshot_name)
3805 if (snapshot_name.empty()) {
3806 snapshot_name = _current_snapshot_name;
3809 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3810 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3812 info << "Loading history from " << xml_path << endmsg;
3814 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3815 info << string_compose (_("%1: no history file \"%2\" for this session."),
3816 _name, xml_path) << endmsg;
3820 if (!tree.read (xml_path)) {
3821 error << string_compose (_("Could not understand session history file \"%1\""),
3822 xml_path) << endmsg;
3829 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3832 UndoTransaction* ut = new UndoTransaction ();
3835 ut->set_name(t->property("name")->value());
3836 stringstream ss(t->property("tv-sec")->value());
3838 ss.str(t->property("tv-usec")->value());
3840 ut->set_timestamp(tv);
3842 for (XMLNodeConstIterator child_it = t->children().begin();
3843 child_it != t->children().end(); child_it++)
3845 XMLNode *n = *child_it;
3848 if (n->name() == "MementoCommand" ||
3849 n->name() == "MementoUndoCommand" ||
3850 n->name() == "MementoRedoCommand") {
3852 if ((c = memento_command_factory(n))) {
3856 } else if (n->name() == "NoteDiffCommand") {
3857 PBD::ID id (n->property("midi-source")->value());
3858 boost::shared_ptr<MidiSource> midi_source =
3859 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3861 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3863 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3866 } else if (n->name() == "SysExDiffCommand") {
3868 PBD::ID id (n->property("midi-source")->value());
3869 boost::shared_ptr<MidiSource> midi_source =
3870 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3872 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3874 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3877 } else if (n->name() == "PatchChangeDiffCommand") {
3879 PBD::ID id (n->property("midi-source")->value());
3880 boost::shared_ptr<MidiSource> midi_source =
3881 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3883 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3885 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3888 } else if (n->name() == "StatefulDiffCommand") {
3889 if ((c = stateful_diff_command_factory (n))) {
3890 ut->add_command (c);
3893 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3904 Session::config_changed (std::string p, bool ours)
3910 if (p == "seamless-loop") {
3912 } else if (p == "rf-speed") {
3914 } else if (p == "auto-loop") {
3916 } else if (p == "session-monitoring") {
3918 } else if (p == "auto-input") {
3920 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3921 /* auto-input only makes a difference if we're rolling */
3922 set_track_monitor_input_status (!config.get_auto_input());
3925 } else if (p == "punch-in") {
3929 if ((location = _locations->auto_punch_location()) != 0) {
3931 if (config.get_punch_in ()) {
3932 replace_event (SessionEvent::PunchIn, location->start());
3934 remove_event (location->start(), SessionEvent::PunchIn);
3938 } else if (p == "punch-out") {
3942 if ((location = _locations->auto_punch_location()) != 0) {
3944 if (config.get_punch_out()) {
3945 replace_event (SessionEvent::PunchOut, location->end());
3947 clear_events (SessionEvent::PunchOut);
3951 } else if (p == "edit-mode") {
3953 Glib::Threads::Mutex::Lock lm (playlists->lock);
3955 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3956 (*i)->set_edit_mode (Config->get_edit_mode ());
3959 } else if (p == "use-video-sync") {
3961 waiting_for_sync_offset = config.get_use_video_sync();
3963 } else if (p == "mmc-control") {
3965 //poke_midi_thread ();
3967 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3969 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3971 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3973 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3975 } else if (p == "midi-control") {
3977 //poke_midi_thread ();
3979 } else if (p == "raid-path") {
3981 setup_raid_path (config.get_raid_path());
3983 } else if (p == "timecode-format") {
3987 } else if (p == "video-pullup") {
3991 } else if (p == "seamless-loop") {
3993 if (play_loop && transport_rolling()) {
3994 // to reset diskstreams etc
3995 request_play_loop (true);
3998 } else if (p == "rf-speed") {
4000 cumulative_rf_motion = 0;
4003 } else if (p == "click-sound") {
4005 setup_click_sounds (1);
4007 } else if (p == "click-emphasis-sound") {
4009 setup_click_sounds (-1);
4011 } else if (p == "clicking") {
4013 if (Config->get_clicking()) {
4014 if (_click_io && click_data) { // don't require emphasis data
4021 } else if (p == "click-record-only") {
4023 _click_rec_only = Config->get_click_record_only();
4025 } else if (p == "click-gain") {
4028 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4031 } else if (p == "send-mtc") {
4033 if (Config->get_send_mtc ()) {
4034 /* mark us ready to send */
4035 next_quarter_frame_to_send = 0;
4038 } else if (p == "send-mmc") {
4040 _mmc->enable_send (Config->get_send_mmc ());
4042 } else if (p == "jack-time-master") {
4044 engine().reset_timebase ();
4046 } else if (p == "native-file-header-format") {
4048 if (!first_file_header_format_reset) {
4049 reset_native_file_format ();
4052 first_file_header_format_reset = false;
4054 } else if (p == "native-file-data-format") {
4056 if (!first_file_data_format_reset) {
4057 reset_native_file_format ();
4060 first_file_data_format_reset = false;
4062 } else if (p == "external-sync") {
4063 if (!config.get_external_sync()) {
4064 drop_sync_source ();
4066 switch_to_sync_source (Config->get_sync_source());
4068 } else if (p == "denormal-model") {
4070 } else if (p == "history-depth") {
4071 set_history_depth (Config->get_history_depth());
4072 } else if (p == "remote-model") {
4073 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4076 } else if (p == "initial-program-change") {
4078 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4081 buf[0] = MIDI::program; // channel zero by default
4082 buf[1] = (Config->get_initial_program_change() & 0x7f);
4084 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4086 } else if (p == "solo-mute-override") {
4087 // catch_up_on_solo_mute_override ();
4088 } else if (p == "listen-position" || p == "pfl-position") {
4089 listen_position_changed ();
4090 } else if (p == "solo-control-is-listen-control") {
4091 solo_control_mode_changed ();
4092 } else if (p == "solo-mute-gain") {
4093 _solo_cut_control->Changed (true, Controllable::NoGroup);
4094 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4095 last_timecode_valid = false;
4096 } else if (p == "playback-buffer-seconds") {
4097 AudioSource::allocate_working_buffers (frame_rate());
4098 } else if (p == "ltc-source-port") {
4099 reconnect_ltc_input ();
4100 } else if (p == "ltc-sink-port") {
4101 reconnect_ltc_output ();
4102 } else if (p == "timecode-generator-offset") {
4103 ltc_tx_parse_offset();
4104 } else if (p == "auto-return-target-list") {
4105 follow_playhead_priority ();
4112 Session::set_history_depth (uint32_t d)
4114 _history.set_depth (d);
4118 Session::load_diskstreams_2X (XMLNode const & node, int)
4121 XMLNodeConstIterator citer;
4123 clist = node.children();
4125 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4128 /* diskstreams added automatically by DiskstreamCreated handler */
4129 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4130 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4131 _diskstreams_2X.push_back (dsp);
4133 error << _("Session: unknown diskstream type in XML") << endmsg;
4137 catch (failed_constructor& err) {
4138 error << _("Session: could not load diskstream via XML state") << endmsg;
4146 /** Connect things to the MMC object */
4148 Session::setup_midi_machine_control ()
4150 _mmc = new MIDI::MachineControl;
4152 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4153 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4155 if (!async_out || !async_out) {
4159 /* XXXX argh, passing raw pointers back into libmidi++ */
4161 MIDI::Port* mmc_in = async_in.get();
4162 MIDI::Port* mmc_out = async_out.get();
4164 _mmc->set_ports (mmc_in, mmc_out);
4166 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4167 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4168 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4169 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4170 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4171 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4172 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4173 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4174 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4175 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4176 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4177 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4178 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4180 /* also handle MIDI SPP because its so common */
4182 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4183 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4184 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4187 boost::shared_ptr<Controllable>
4188 Session::solo_cut_control() const
4190 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4191 controls in Ardour that currently get presented to the user in the GUI that require
4192 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4194 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4195 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4199 return _solo_cut_control;
4203 Session::save_snapshot_name (const std::string & n)
4205 /* assure Stateful::_instant_xml is loaded
4206 * add_instant_xml() only adds to existing data and defaults
4207 * to use an empty Tree otherwise
4209 instant_xml ("LastUsedSnapshot");
4211 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4212 last_used_snapshot->set_property ("name", n);
4213 add_instant_xml (*last_used_snapshot, false);
4217 Session::set_snapshot_name (const std::string & n)
4219 _current_snapshot_name = n;
4220 save_snapshot_name (n);
4224 Session::rename (const std::string& new_name)
4226 string legal_name = legalize_for_path (new_name);
4232 string const old_sources_root = _session_dir->sources_root();
4234 if (!_writable || (_state_of_the_state & CannotSave)) {
4235 error << _("Cannot rename read-only session.") << endmsg;
4236 return 0; // don't show "messed up" warning
4238 if (record_status() == Recording) {
4239 error << _("Cannot rename session while recording") << endmsg;
4240 return 0; // don't show "messed up" warning
4243 StateProtector stp (this);
4248 * interchange subdirectory
4252 * Backup files are left unchanged and not renamed.
4255 /* Windows requires that we close all files before attempting the
4256 * rename. This works on other platforms, but isn't necessary there.
4257 * Leave it in place for all platforms though, since it may help
4258 * catch issues that could arise if the way Source files work ever
4259 * change (since most developers are not using Windows).
4262 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4263 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4269 /* pass one: not 100% safe check that the new directory names don't
4273 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4277 /* this is a stupid hack because Glib::path_get_dirname() is
4278 * lexical-only, and so passing it /a/b/c/ gives a different
4279 * result than passing it /a/b/c ...
4282 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4283 oldstr = oldstr.substr (0, oldstr.length() - 1);
4286 string base = Glib::path_get_dirname (oldstr);
4288 newstr = Glib::build_filename (base, legal_name);
4290 cerr << "Looking for " << newstr << endl;
4292 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4293 cerr << " exists\n";
4302 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4308 /* this is a stupid hack because Glib::path_get_dirname() is
4309 * lexical-only, and so passing it /a/b/c/ gives a different
4310 * result than passing it /a/b/c ...
4313 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4314 oldstr = oldstr.substr (0, oldstr.length() - 1);
4317 string base = Glib::path_get_dirname (oldstr);
4318 newstr = Glib::build_filename (base, legal_name);
4320 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4322 cerr << "Rename " << oldstr << " => " << newstr << endl;
4323 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4324 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4325 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4329 /* Reset path in "session dirs" */
4334 /* reset primary SessionDirectory object */
4337 (*_session_dir) = newstr;
4342 /* now rename directory below session_dir/interchange */
4344 string old_interchange_dir;
4345 string new_interchange_dir;
4347 /* use newstr here because we renamed the path
4348 * (folder/directory) that used to be oldstr to newstr above
4351 v.push_back (newstr);
4352 v.push_back (interchange_dir_name);
4353 v.push_back (Glib::path_get_basename (oldstr));
4355 old_interchange_dir = Glib::build_filename (v);
4358 v.push_back (newstr);
4359 v.push_back (interchange_dir_name);
4360 v.push_back (legal_name);
4362 new_interchange_dir = Glib::build_filename (v);
4364 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4366 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4367 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4368 old_interchange_dir, new_interchange_dir,
4371 error << string_compose (_("renaming %s as %2 failed (%3)"),
4372 old_interchange_dir, new_interchange_dir,
4381 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4382 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4384 cerr << "Rename " << oldstr << " => " << newstr << endl;
4386 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4387 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4388 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4394 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4396 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4397 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4399 cerr << "Rename " << oldstr << " => " << newstr << endl;
4401 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4402 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4403 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4408 /* remove old name from recent sessions */
4409 remove_recent_sessions (_path);
4412 /* update file source paths */
4414 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4415 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4417 string p = fs->path ();
4418 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4420 SourceFactory::setup_peakfile(i->second, true);
4424 set_snapshot_name (new_name);
4429 /* save state again to get everything just right */
4431 save_state (_current_snapshot_name);
4433 /* add to recent sessions */
4435 store_recent_sessions (new_name, _path);
4441 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4443 bool found_sr = false;
4444 bool found_data_format = false;
4445 program_version = "";
4447 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4451 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4455 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4458 xmlFreeParserCtxt(ctxt);
4462 xmlNodePtr node = xmlDocGetRootElement(doc);
4465 xmlFreeParserCtxt(ctxt);
4473 for (attr = node->properties; attr; attr = attr->next) {
4474 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4475 sample_rate = atoi ((char*)attr->children->content);
4480 node = node->children;
4481 while (node != NULL) {
4482 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4483 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4485 program_version = string ((const char*)val);
4486 size_t sep = program_version.find_first_of("-");
4487 if (sep != string::npos) {
4488 program_version = program_version.substr (0, sep);
4493 if (strcmp((const char*) node->name, "Config")) {
4497 for (node = node->children; node; node = node->next) {
4498 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4499 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4501 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4503 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4505 found_data_format = true;
4515 xmlFreeParserCtxt(ctxt);
4518 return !(found_sr && found_data_format); // zero if they are both found
4522 Session::get_snapshot_from_instant (const std::string& session_dir)
4524 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4526 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4531 if (!tree.read (instant_xml_path)) {
4535 XMLProperty const * prop;
4536 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4537 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4538 return prop->value();
4544 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4545 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4548 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4552 SourcePathMap source_path_map;
4554 boost::shared_ptr<AudioFileSource> afs;
4559 Glib::Threads::Mutex::Lock lm (source_lock);
4561 cerr << " total sources = " << sources.size();
4563 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4564 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4570 if (fs->within_session()) {
4574 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4575 source_path_map[fs->path()].push_back (fs);
4577 SeveralFileSources v;
4579 source_path_map.insert (make_pair (fs->path(), v));
4585 cerr << " fsources = " << total << endl;
4587 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4589 /* tell caller where we are */
4591 string old_path = i->first;
4593 callback (n, total, old_path);
4595 cerr << old_path << endl;
4599 switch (i->second.front()->type()) {
4600 case DataType::AUDIO:
4601 new_path = new_audio_source_path_for_embedded (old_path);
4604 case DataType::MIDI:
4605 /* XXX not implemented yet */
4609 if (new_path.empty()) {
4613 cerr << "Move " << old_path << " => " << new_path << endl;
4615 if (!copy_file (old_path, new_path)) {
4616 cerr << "failed !\n";
4620 /* make sure we stop looking in the external
4621 dir/folder. Remember, this is an all-or-nothing
4622 operations, it doesn't merge just some files.
4624 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4626 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4627 (*f)->set_path (new_path);
4632 save_state ("", false, false);
4638 bool accept_all_files (string const &, void *)
4644 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4646 /* 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.
4651 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4653 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4655 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4657 v.push_back (new_session_folder); /* full path */
4658 v.push_back (interchange_dir_name);
4659 v.push_back (new_session_path); /* just one directory/folder */
4660 v.push_back (typedir);
4661 v.push_back (Glib::path_get_basename (old_path));
4663 return Glib::build_filename (v);
4667 Session::save_as (SaveAs& saveas)
4669 vector<string> files;
4670 string current_folder = Glib::path_get_dirname (_path);
4671 string new_folder = legalize_for_path (saveas.new_name);
4672 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4673 int64_t total_bytes = 0;
4677 int32_t internal_file_cnt = 0;
4679 vector<string> do_not_copy_extensions;
4680 do_not_copy_extensions.push_back (statefile_suffix);
4681 do_not_copy_extensions.push_back (pending_suffix);
4682 do_not_copy_extensions.push_back (backup_suffix);
4683 do_not_copy_extensions.push_back (temp_suffix);
4684 do_not_copy_extensions.push_back (history_suffix);
4686 /* get total size */
4688 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4690 /* need to clear this because
4691 * find_files_matching_filter() is cumulative
4696 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4698 all += files.size();
4700 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4702 g_stat ((*i).c_str(), &gsb);
4703 total_bytes += gsb.st_size;
4707 /* save old values so we can switch back if we are not switching to the new session */
4709 string old_path = _path;
4710 string old_name = _name;
4711 string old_snapshot = _current_snapshot_name;
4712 string old_sd = _session_dir->root_path();
4713 vector<string> old_search_path[DataType::num_types];
4714 string old_config_search_path[DataType::num_types];
4716 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4717 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4718 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4719 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4721 /* switch session directory */
4723 (*_session_dir) = to_dir;
4725 /* create new tree */
4727 if (!_session_dir->create()) {
4728 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4733 /* copy all relevant files. Find each location in session_dirs,
4734 * and copy files from there to target.
4737 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4739 /* need to clear this because
4740 * find_files_matching_filter() is cumulative
4745 const size_t prefix_len = (*sd).path.size();
4747 /* Work just on the files within this session dir */
4749 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4751 /* add dir separator to protect against collisions with
4752 * track names (e.g. track named "audiofiles" or
4756 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4757 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4758 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4760 /* copy all the files. Handling is different for media files
4761 than others because of the *silly* subtree we have below the interchange
4762 folder. That really was a bad idea, but I'm not fixing it as part of
4763 implementing ::save_as().
4766 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4768 std::string from = *i;
4771 string filename = Glib::path_get_basename (from);
4772 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4773 if (filename == ".DS_STORE") {
4778 if (from.find (audiofile_dir_string) != string::npos) {
4780 /* audio file: only copy if asked */
4782 if (saveas.include_media && saveas.copy_media) {
4784 string to = make_new_media_path (*i, to_dir, new_folder);
4786 info << "media file copying from " << from << " to " << to << endmsg;
4788 if (!copy_file (from, to)) {
4789 throw Glib::FileError (Glib::FileError::IO_ERROR,
4790 string_compose(_("\ncopying \"%1\" failed !"), from));
4794 /* we found media files inside the session folder */
4796 internal_file_cnt++;
4798 } else if (from.find (midifile_dir_string) != string::npos) {
4800 /* midi file: always copy unless
4801 * creating an empty new session
4804 if (saveas.include_media) {
4806 string to = make_new_media_path (*i, to_dir, new_folder);
4808 info << "media file copying from " << from << " to " << to << endmsg;
4810 if (!copy_file (from, to)) {
4811 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4815 /* we found media files inside the session folder */
4817 internal_file_cnt++;
4819 } else if (from.find (analysis_dir_string) != string::npos) {
4821 /* make sure analysis dir exists in
4822 * new session folder, but we're not
4823 * copying analysis files here, see
4827 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4832 /* normal non-media file. Don't copy state, history, etc.
4835 bool do_copy = true;
4837 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4838 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4839 /* end of filename matches extension, do not copy file */
4845 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4846 /* don't copy peakfiles if
4847 * we're not copying media
4853 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4855 info << "attempting to make directory/folder " << to << endmsg;
4857 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4858 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4861 info << "attempting to copy " << from << " to " << to << endmsg;
4863 if (!copy_file (from, to)) {
4864 throw Glib::FileError (Glib::FileError::IO_ERROR,
4865 string_compose(_("\ncopying \"%1\" failed !"), from));
4870 /* measure file size even if we're not going to copy so that our Progress
4871 signals are correct, since we included these do-not-copy files
4872 in the computation of the total size and file count.
4876 g_stat (from.c_str(), &gsb);
4877 copied += gsb.st_size;
4880 double fraction = (double) copied / total_bytes;
4882 bool keep_going = true;
4884 if (saveas.copy_media) {
4886 /* no need or expectation of this if
4887 * media is not being copied, because
4888 * it will be fast(ish).
4891 /* tell someone "X percent, file M of N"; M is one-based */
4893 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4901 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4907 /* copy optional folders, if any */
4909 string old = plugins_dir ();
4910 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4911 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4912 copy_files (old, newdir);
4915 old = externals_dir ();
4916 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4917 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4918 copy_files (old, newdir);
4921 old = automation_dir ();
4922 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4923 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4924 copy_files (old, newdir);
4927 if (saveas.include_media) {
4929 if (saveas.copy_media) {
4930 #ifndef PLATFORM_WINDOWS
4931 /* There are problems with analysis files on
4932 * Windows, because they used a colon in their
4933 * names as late as 4.0. Colons are not legal
4934 * under Windows even if NTFS allows them.
4936 * This is a tricky problem to solve so for
4937 * just don't copy these files. They will be
4938 * regenerated as-needed anyway, subject to the
4939 * existing issue that the filenames will be
4940 * rejected by Windows, which is a separate
4941 * problem (though related).
4944 /* only needed if we are copying media, since the
4945 * analysis data refers to media data
4948 old = analysis_dir ();
4949 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4950 string newdir = Glib::build_filename (to_dir, "analysis");
4951 copy_files (old, newdir);
4953 #endif /* PLATFORM_WINDOWS */
4958 set_snapshot_name (saveas.new_name);
4959 _name = saveas.new_name;
4961 if (saveas.include_media && !saveas.copy_media) {
4963 /* reset search paths of the new session (which we're pretending to be right now) to
4964 include the original session search path, so we can still find all audio.
4967 if (internal_file_cnt) {
4968 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4969 ensure_search_path_includes (*s, DataType::AUDIO);
4970 cerr << "be sure to include " << *s << " for audio" << endl;
4973 /* we do not do this for MIDI because we copy
4974 all MIDI files if saveas.include_media is
4980 bool was_dirty = dirty ();
4982 save_default_options ();
4984 if (saveas.copy_media && saveas.copy_external) {
4985 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4986 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4990 saveas.final_session_folder_name = _path;
4992 store_recent_sessions (_name, _path);
4994 if (!saveas.switch_to) {
4996 /* save the new state */
4998 save_state ("", false, false, !saveas.include_media);
5000 /* switch back to the way things were */
5004 set_snapshot_name (old_snapshot);
5006 (*_session_dir) = old_sd;
5012 if (internal_file_cnt) {
5013 /* reset these to their original values */
5014 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5015 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5020 /* prune session dirs, and update disk space statistics
5025 session_dirs.clear ();
5026 session_dirs.push_back (sp);
5027 refresh_disk_space ();
5029 /* ensure that all existing tracks reset their current capture source paths
5031 reset_write_sources (true, true);
5033 /* creating new write sources marks the session as
5034 dirty. If the new session is empty, then
5035 save_state() thinks we're saving a template and will
5036 not mark the session as clean. So do that here,
5037 before we save state.
5040 if (!saveas.include_media) {
5041 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5044 save_state ("", false, false, !saveas.include_media);
5046 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5047 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5050 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5051 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5057 if (fs->within_session()) {
5058 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5059 fs->set_path (newpath);
5064 } catch (Glib::FileError& e) {
5066 saveas.failure_message = e.what();
5068 /* recursively remove all the directories */
5070 remove_directory (to_dir);
5078 saveas.failure_message = _("unknown reason");
5080 /* recursively remove all the directories */
5082 remove_directory (to_dir);
5092 static void set_progress (Progress* p, size_t n, size_t t)
5094 p->set_progress (float (n) / float(t));
5098 Session::archive_session (const std::string& dest,
5099 const std::string& name,
5100 ArchiveEncode compress_audio,
5101 bool only_used_sources,
5104 if (dest.empty () || name.empty ()) {
5108 /* save current values */
5109 bool was_dirty = dirty ();
5110 string old_path = _path;
5111 string old_name = _name;
5112 string old_snapshot = _current_snapshot_name;
5113 string old_sd = _session_dir->root_path();
5114 string old_config_search_path[DataType::num_types];
5115 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5116 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5118 /* ensure that session-path is included in search-path */
5120 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5121 if ((*sd).path == old_path) {
5129 /* create temporary dir to save session to */
5130 #ifdef PLATFORM_WINDOWS
5131 char tmp[256] = "C:\\TEMP\\";
5132 GetTempPath (sizeof (tmp), tmp);
5134 char const* tmp = getenv("TMPDIR");
5139 if ((strlen (tmp) + 21) > 1024) {
5144 strcpy (tmptpl, tmp);
5145 strcat (tmptpl, "ardourarchive-XXXXXX");
5146 char* tmpdir = g_mkdtemp (tmptpl);
5152 std::string to_dir = std::string (tmpdir);
5154 /* switch session directory temporarily */
5155 (*_session_dir) = to_dir;
5157 if (!_session_dir->create()) {
5158 (*_session_dir) = old_sd;
5159 remove_directory (to_dir);
5163 /* prepare archive */
5164 string archive = Glib::build_filename (dest, name + ".tar.xz");
5166 PBD::ScopedConnectionList progress_connection;
5167 PBD::FileArchive ar (archive);
5169 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5172 /* collect files to archive */
5173 std::map<string,string> filemap;
5175 vector<string> do_not_copy_extensions;
5176 do_not_copy_extensions.push_back (statefile_suffix);
5177 do_not_copy_extensions.push_back (pending_suffix);
5178 do_not_copy_extensions.push_back (backup_suffix);
5179 do_not_copy_extensions.push_back (temp_suffix);
5180 do_not_copy_extensions.push_back (history_suffix);
5182 vector<string> blacklist_dirs;
5183 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5184 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5185 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5186 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5187 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5188 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5190 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5191 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5193 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5194 if (only_used_sources) {
5195 playlists->sync_all_regions_with_regions ();
5196 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5199 // collect audio sources for this session, calc total size for encoding
5200 // add option to only include *used* sources (see Session::cleanup_sources)
5201 size_t total_size = 0;
5203 Glib::Threads::Mutex::Lock lm (source_lock);
5204 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5205 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5206 if (!afs || afs->readable_length () == 0) {
5210 if (only_used_sources) {
5214 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5219 std::string from = afs->path();
5221 if (compress_audio != NO_ENCODE) {
5222 total_size += afs->readable_length ();
5224 if (afs->within_session()) {
5225 filemap[from] = make_new_media_path (from, name, name);
5227 filemap[from] = make_new_media_path (from, name, name);
5228 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5235 if (compress_audio != NO_ENCODE) {
5237 progress->set_progress (2); // set to "encoding"
5238 progress->set_progress (0);
5241 Glib::Threads::Mutex::Lock lm (source_lock);
5242 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5243 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5244 if (!afs || afs->readable_length () == 0) {
5248 if (only_used_sources) {
5252 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5257 orig_sources[afs] = afs->path();
5258 orig_gain[afs] = afs->gain();
5260 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5261 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5262 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5265 progress->descend ((float)afs->readable_length () / total_size);
5269 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5270 afs->replace_file (new_path);
5271 afs->set_gain (ns->gain(), true);
5274 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5278 progress->ascend ();
5284 progress->set_progress (-1); // set to "archiving"
5285 progress->set_progress (0);
5288 /* index files relevant for this session */
5289 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5290 vector<string> files;
5292 size_t prefix_len = (*sd).path.size();
5293 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5297 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5299 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5300 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5301 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5303 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5304 std::string from = *i;
5307 string filename = Glib::path_get_basename (from);
5308 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5309 if (filename == ".DS_STORE") {
5314 if (from.find (audiofile_dir_string) != string::npos) {
5316 } else if (from.find (midifile_dir_string) != string::npos) {
5317 filemap[from] = make_new_media_path (from, name, name);
5318 } else if (from.find (videofile_dir_string) != string::npos) {
5319 filemap[from] = make_new_media_path (from, name, name);
5321 bool do_copy = true;
5322 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5323 if (from.find (*v) != string::npos) {
5328 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5329 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5336 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5342 /* write session file */
5344 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5346 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5349 save_default_options ();
5351 size_t prefix_len = _path.size();
5352 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5356 /* collect session-state files */
5357 vector<string> files;
5358 do_not_copy_extensions.clear ();
5359 do_not_copy_extensions.push_back (history_suffix);
5361 blacklist_dirs.clear ();
5362 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5364 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5365 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5366 std::string from = *i;
5367 bool do_copy = true;
5368 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5369 if (from.find (*v) != string::npos) {
5374 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5375 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5381 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5385 /* restore original values */
5388 set_snapshot_name (old_snapshot);
5389 (*_session_dir) = old_sd;
5393 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5394 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5396 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5397 i->first->replace_file (i->second);
5399 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5400 i->first->set_gain (i->second, true);
5403 int rv = ar.create (filemap);
5404 remove_directory (to_dir);
5410 Session::undo (uint32_t n)
5412 if (actively_recording()) {
5420 Session::redo (uint32_t n)
5422 if (actively_recording()) {