2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/sndfilesource.h"
124 #include "ardour/source_factory.h"
125 #include "ardour/speakers.h"
126 #include "ardour/template_utils.h"
127 #include "ardour/tempo.h"
128 #include "ardour/ticker.h"
129 #include "ardour/user_bundle.h"
130 #include "ardour/vca.h"
131 #include "ardour/vca_manager.h"
133 #include "control_protocol/control_protocol.h"
135 #include "LuaBridge/LuaBridge.h"
137 #include "pbd/i18n.h"
141 using namespace ARDOUR;
144 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
147 Session::pre_engine_init (string fullpath)
149 if (fullpath.empty()) {
151 throw failed_constructor();
154 /* discover canonical fullpath */
156 _path = canonical_path(fullpath);
159 if (Profile->get_trx() ) {
160 // Waves TracksLive has a usecase of session replacement with a new one.
161 // We should check session state file (<session_name>.ardour) existance
162 // to determine if the session is new or not
164 string full_session_name = Glib::build_filename( fullpath, _name );
165 full_session_name += statefile_suffix;
167 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
169 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 /* finish initialization that can't be done in a normal C++ constructor
176 timerclear (&last_mmc_step);
177 g_atomic_int_set (&processing_prohibited, 0);
178 g_atomic_int_set (&_record_status, Disabled);
179 g_atomic_int_set (&_playback_load, 100);
180 g_atomic_int_set (&_capture_load, 100);
182 _all_route_group->set_active (true, this);
183 interpolation.add_channel_to (0, 0);
185 if (config.get_use_video_sync()) {
186 waiting_for_sync_offset = true;
188 waiting_for_sync_offset = false;
191 last_rr_session_dir = session_dirs.begin();
193 set_history_depth (Config->get_history_depth());
195 /* default: assume simple stereo speaker configuration */
197 _speakers->setup_default_speakers (2);
199 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
200 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
201 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
202 add_controllable (_solo_cut_control);
204 /* These are all static "per-class" signals */
206 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
207 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
208 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
209 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
210 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
212 /* stop IO objects from doing stuff until we're ready for them */
214 Delivery::disable_panners ();
215 IO::disable_connecting ();
219 Session::post_engine_init ()
221 BootMessage (_("Set block size and sample rate"));
223 set_block_size (_engine.samples_per_cycle());
224 set_frame_rate (_engine.sample_rate());
226 BootMessage (_("Using configuration"));
228 _midi_ports = new MidiPortManager;
230 MIDISceneChanger* msc;
232 _scene_changer = msc = new MIDISceneChanger (*this);
233 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
234 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
236 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
237 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
239 setup_midi_machine_control ();
241 if (_butler->start_thread()) {
242 error << _("Butler did not start") << endmsg;
246 if (start_midi_thread ()) {
247 error << _("MIDI I/O thread did not start") << endmsg;
251 setup_click_sounds (0);
252 setup_midi_control ();
254 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
255 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
258 /* tempo map requires sample rate knowledge */
261 _tempo_map = new TempoMap (_current_frame_rate);
262 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
263 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 /* MidiClock requires a tempo map */
268 midi_clock = new MidiClockTicker ();
269 midi_clock->set_session (this);
271 /* crossfades require sample rate knowledge */
273 SndFileSource::setup_standard_crossfades (*this, frame_rate());
274 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
275 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
277 AudioDiskstream::allocate_working_buffers();
278 refresh_disk_space ();
280 /* we're finally ready to call set_state() ... all objects have
281 * been created, the engine is running.
285 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
286 error << _("Could not set session state from XML") << endmsg;
290 // set_state() will call setup_raid_path(), but if it's a new session we need
291 // to call setup_raid_path() here.
292 setup_raid_path (_path);
297 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
298 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
300 Config->map_parameters (ff);
301 config.map_parameters (ft);
302 _butler->map_parameters ();
304 /* Reset all panners */
306 Delivery::reset_panners ();
308 /* this will cause the CPM to instantiate any protocols that are in use
309 * (or mandatory), which will pass it this Session, and then call
310 * set_state() on each instantiated protocol to match stored state.
313 ControlProtocolManager::instance().set_session (this);
315 /* This must be done after the ControlProtocolManager set_session above,
316 as it will set states for ports which the ControlProtocolManager creates.
319 // XXX set state of MIDI::Port's
320 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
322 /* And this must be done after the MIDI::Manager::set_port_states as
323 * it will try to make connections whose details are loaded by set_port_states.
328 /* Let control protocols know that we are now all connected, so they
329 * could start talking to surfaces if they want to.
332 ControlProtocolManager::instance().midi_connectivity_established ();
334 if (_is_new && !no_auto_connect()) {
335 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
336 auto_connect_master_bus ();
339 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
341 /* update latencies */
343 initialize_latencies ();
345 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
346 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
347 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
349 } catch (AudioEngine::PortRegistrationFailure& err) {
350 /* handle this one in a different way than all others, so that its clear what happened */
351 error << err.what() << endmsg;
353 } catch (std::exception const & e) {
354 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
357 error << _("Unknown exception during session setup") << endmsg;
361 BootMessage (_("Reset Remote Controls"));
363 // send_full_time_code (0);
364 _engine.transport_locate (0);
366 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
367 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
369 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
372 /* initial program change will be delivered later; see ::config_changed() */
374 _state_of_the_state = Clean;
376 Port::set_connecting_blocked (false);
378 DirtyChanged (); /* EMIT SIGNAL */
382 } else if (state_was_pending) {
384 remove_pending_capture_state ();
385 state_was_pending = false;
388 /* Now, finally, we can fill the playback buffers */
390 BootMessage (_("Filling playback buffers"));
392 boost::shared_ptr<RouteList> rl = routes.reader();
393 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
394 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
395 if (trk && !trk->hidden()) {
396 trk->seek (_transport_frame, true);
404 Session::session_loaded ()
408 _state_of_the_state = Clean;
410 DirtyChanged (); /* EMIT SIGNAL */
414 } else if (state_was_pending) {
416 remove_pending_capture_state ();
417 state_was_pending = false;
420 /* Now, finally, we can fill the playback buffers */
422 BootMessage (_("Filling playback buffers"));
423 force_locate (_transport_frame, false);
427 Session::raid_path () const
429 Searchpath raid_search_path;
431 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
432 raid_search_path += (*i).path;
435 return raid_search_path.to_string ();
439 Session::setup_raid_path (string path)
448 session_dirs.clear ();
450 Searchpath search_path(path);
451 Searchpath sound_search_path;
452 Searchpath midi_search_path;
454 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
456 sp.blocks = 0; // not needed
457 session_dirs.push_back (sp);
459 SessionDirectory sdir(sp.path);
461 sound_search_path += sdir.sound_path ();
462 midi_search_path += sdir.midi_path ();
465 // reset the round-robin soundfile path thingie
466 last_rr_session_dir = session_dirs.begin();
470 Session::path_is_within_session (const std::string& path)
472 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
473 if (PBD::path_is_within (i->path, path)) {
481 Session::ensure_subdirs ()
485 dir = session_directory().peak_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().sound_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = session_directory().midi_path();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = session_directory().dead_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().export_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = analysis_dir ();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = plugins_dir ();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = externals_dir ();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
544 /** @param session_template directory containing session template, or empty.
545 * Caller must not hold process lock.
548 Session::create (const string& session_template, BusProfile* bus_profile)
550 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
551 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
555 if (ensure_subdirs ()) {
559 _writable = exists_and_writable (_path);
561 if (!session_template.empty()) {
562 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
564 FILE* in = g_fopen (in_path.c_str(), "rb");
567 /* no need to call legalize_for_path() since the string
568 * in session_template is already a legal path name
570 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
572 FILE* out = g_fopen (out_path.c_str(), "wb");
576 stringstream new_session;
579 size_t charsRead = fread (buf, sizeof(char), 1024, in);
582 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
587 if (charsRead == 0) {
590 new_session.write (buf, charsRead);
594 string file_contents = new_session.str();
595 size_t writeSize = file_contents.length();
596 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
597 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
605 if (!ARDOUR::Profile->get_trx()) {
606 /* Copy plugin state files from template to new session */
607 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
608 copy_recurse (template_plugins, plugins_dir ());
614 error << string_compose (_("Could not open %1 for writing session template"), out_path)
621 error << string_compose (_("Could not open session template %1 for reading"), in_path)
628 if (Profile->get_trx()) {
630 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
631 Remember that this is a brand new session. Sessions
632 loaded from saved state will get this range from the saved state.
635 set_session_range_location (0, 0);
637 /* Initial loop location, from absolute zero, length 10 seconds */
639 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
640 _locations->add (loc, true);
641 set_auto_loop_location (loc);
644 _state_of_the_state = Clean;
646 /* set up Master Out and Monitor Out if necessary */
651 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
653 // Waves Tracks: always create master bus for Tracks
654 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
655 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
663 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
664 r->input()->ensure_io (count, false, this);
665 r->output()->ensure_io (count, false, this);
671 /* prohibit auto-connect to master, because there isn't one */
672 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
676 add_routes (rl, false, false, false, PresentationInfo::max_order);
679 // Waves Tracks: Skip this. Always use autoconnection for Tracks
680 if (!ARDOUR::Profile->get_trx()) {
682 /* this allows the user to override settings with an environment variable.
685 if (no_auto_connect()) {
686 bus_profile->input_ac = AutoConnectOption (0);
687 bus_profile->output_ac = AutoConnectOption (0);
690 Config->set_input_auto_connect (bus_profile->input_ac);
691 Config->set_output_auto_connect (bus_profile->output_ac);
695 if (Config->get_use_monitor_bus() && bus_profile) {
696 add_monitor_section ();
703 Session::maybe_write_autosave()
705 if (dirty() && record_status() != Recording) {
706 save_state("", true);
711 Session::remove_pending_capture_state ()
713 std::string pending_state_file_path(_session_dir->root_path());
715 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
717 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
719 if (g_remove (pending_state_file_path.c_str()) != 0) {
720 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
721 pending_state_file_path, g_strerror (errno)) << endmsg;
725 /** Rename a state file.
726 * @param old_name Old snapshot name.
727 * @param new_name New snapshot name.
730 Session::rename_state (string old_name, string new_name)
732 if (old_name == _current_snapshot_name || old_name == _name) {
733 /* refuse to rename the current snapshot or the "main" one */
737 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
738 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
740 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
741 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
743 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
744 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
745 old_name, new_name, g_strerror(errno)) << endmsg;
749 /** Remove a state file.
750 * @param snapshot_name Snapshot name.
753 Session::remove_state (string snapshot_name)
755 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
756 // refuse to remove the current snapshot or the "main" one
760 std::string xml_path(_session_dir->root_path());
762 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
764 if (!create_backup_file (xml_path)) {
765 // don't remove it if a backup can't be made
766 // create_backup_file will log the error.
771 if (g_remove (xml_path.c_str()) != 0) {
772 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
773 xml_path, g_strerror (errno)) << endmsg;
777 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
779 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
781 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
784 std::string xml_path(_session_dir->root_path());
786 /* prevent concurrent saves from different threads */
788 Glib::Threads::Mutex::Lock lm (save_state_lock);
790 if (!_writable || (_state_of_the_state & CannotSave)) {
794 if (g_atomic_int_get(&_suspend_save)) {
798 _save_queued = false;
800 if (!_engine.connected ()) {
801 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
808 const int64_t save_start_time = g_get_monotonic_time();
811 /* tell sources we're saving first, in case they write out to a new file
812 * which should be saved with the state rather than the old one */
813 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
815 i->second->session_saved();
816 } catch (Evoral::SMF::FileError& e) {
817 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
821 SessionSaveUnderway (); /* EMIT SIGNAL */
823 bool mark_as_clean = true;
825 if (!snapshot_name.empty() && !switch_to_snapshot) {
826 mark_as_clean = false;
830 mark_as_clean = false;
831 tree.set_root (&get_template());
833 tree.set_root (&get_state());
836 if (snapshot_name.empty()) {
837 snapshot_name = _current_snapshot_name;
838 } else if (switch_to_snapshot) {
839 set_snapshot_name (snapshot_name);
842 assert (!snapshot_name.empty());
846 /* proper save: use statefile_suffix (.ardour in English) */
848 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
850 /* make a backup copy of the old file */
852 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
853 // create_backup_file will log the error
859 /* pending save: use pending_suffix (.pending in English) */
860 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
863 std::string tmp_path(_session_dir->root_path());
864 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
866 cerr << "actually writing state to " << tmp_path << endl;
868 if (!tree.write (tmp_path)) {
869 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 cerr << "renaming state to " << xml_path << endl;
880 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
881 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
882 tmp_path, xml_path, g_strerror(errno)) << endmsg;
883 if (g_remove (tmp_path.c_str()) != 0) {
884 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
885 tmp_path, g_strerror (errno)) << endmsg;
893 save_history (snapshot_name);
896 bool was_dirty = dirty();
898 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
901 DirtyChanged (); /* EMIT SIGNAL */
905 StateSaved (snapshot_name); /* EMIT SIGNAL */
909 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
910 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
916 Session::restore_state (string snapshot_name)
918 if (load_state (snapshot_name) == 0) {
919 set_state (*state_tree->root(), Stateful::loading_state_version);
926 Session::load_state (string snapshot_name)
931 state_was_pending = false;
933 /* check for leftover pending state from a crashed capture attempt */
935 std::string xmlpath(_session_dir->root_path());
936 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
938 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 /* there is pending state from a crashed capture attempt */
942 boost::optional<int> r = AskAboutPendingState();
943 if (r.get_value_or (1)) {
944 state_was_pending = true;
948 if (!state_was_pending) {
949 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
952 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
953 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
954 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
955 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
960 state_tree = new XMLTree;
964 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
966 if (!state_tree->read (xmlpath)) {
967 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
973 XMLNode const & root (*state_tree->root());
975 if (root.name() != X_("Session")) {
976 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
982 XMLProperty const * prop;
984 if ((prop = root.property ("version")) == 0) {
985 /* no version implies very old version of Ardour */
986 Stateful::loading_state_version = 1000;
988 if (prop->value().find ('.') != string::npos) {
989 /* old school version format */
990 if (prop->value()[0] == '2') {
991 Stateful::loading_state_version = 2000;
993 Stateful::loading_state_version = 3000;
996 Stateful::loading_state_version = atoi (prop->value());
1000 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1002 std::string backup_path(_session_dir->root_path());
1003 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1004 backup_path = Glib::build_filename (backup_path, backup_filename);
1006 // only create a backup for a given statefile version once
1008 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1010 VersionMismatch (xmlpath, backup_path);
1012 if (!copy_file (xmlpath, backup_path)) {;
1018 save_snapshot_name (snapshot_name);
1024 Session::load_options (const XMLNode& node)
1027 config.set_variables (node);
1032 Session::save_default_options ()
1034 return config.save_state();
1038 Session::get_state()
1044 Session::get_template()
1046 /* if we don't disable rec-enable, diskstreams
1047 will believe they need to store their capture
1048 sources in their state node.
1051 disable_record (false);
1053 return state(false);
1056 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1057 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1060 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1062 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1065 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1069 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1072 XMLNode* node = new XMLNode("TrackState"); // XXX
1075 PlaylistSet playlists; // SessionPlaylists
1078 // these will work with new_route_from_template()
1079 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1080 child = node->add_child ("Routes");
1081 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1082 if ((*i)->is_auditioner()) {
1085 if ((*i)->is_master() || (*i)->is_monitor()) {
1088 child->add_child_nocopy ((*i)->get_state());
1089 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1091 playlists.insert (track->playlist ());
1095 // on load, Regions in the playlists need to resolve and map Source-IDs
1096 // also playlist needs to be merged or created with new-name..
1097 // ... and Diskstream in tracks adjusted to use the correct playlist
1098 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1099 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1100 child->add_child_nocopy ((*i)->get_state ());
1101 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1102 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1103 const Region::SourceList& sl = (*s)->sources ();
1104 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1105 sources.insert (*sli);
1110 child = node->add_child ("Sources");
1111 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1112 child->add_child_nocopy ((*i)->get_state ());
1113 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1115 #ifdef PLATFORM_WINDOWS
1118 string p = fs->path ();
1119 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1123 std::string sn = Glib::build_filename (path, "share.axml");
1126 tree.set_root (node);
1127 return tree.write (sn.c_str());
1131 Session::state (bool full_state)
1134 XMLNode* node = new XMLNode("Session");
1138 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1139 node->add_property("version", buf);
1141 child = node->add_child ("ProgramVersion");
1142 child->add_property("created-with", created_with);
1144 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1145 child->add_property("modified-with", modified_with);
1147 /* store configuration settings */
1151 node->add_property ("name", _name);
1152 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1153 node->add_property ("sample-rate", buf);
1155 if (session_dirs.size() > 1) {
1159 vector<space_and_path>::iterator i = session_dirs.begin();
1160 vector<space_and_path>::iterator next;
1162 ++i; /* skip the first one */
1166 while (i != session_dirs.end()) {
1170 if (next != session_dirs.end()) {
1171 p += G_SEARCHPATH_SEPARATOR;
1180 child = node->add_child ("Path");
1181 child->add_content (p);
1185 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1187 /* save the ID counter */
1189 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1190 node->add_property ("id-counter", buf);
1192 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1193 node->add_property ("name-counter", buf);
1195 /* save the event ID counter */
1197 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1198 node->add_property ("event-counter", buf);
1200 /* save the VCA counter */
1202 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1203 node->add_property ("vca-counter", buf);
1205 /* various options */
1207 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1208 if (!midi_port_nodes.empty()) {
1209 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1210 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1211 midi_port_stuff->add_child_nocopy (**n);
1213 node->add_child_nocopy (*midi_port_stuff);
1216 XMLNode& cfgxml (config.get_variables ());
1218 /* exclude search-paths from template */
1219 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1220 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1221 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1223 node->add_child_nocopy (cfgxml);
1225 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1227 child = node->add_child ("Sources");
1230 Glib::Threads::Mutex::Lock sl (source_lock);
1232 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1234 /* Don't save information about non-file Sources, or
1235 * about non-destructive file sources that are empty
1236 * and unused by any regions.
1239 boost::shared_ptr<FileSource> fs;
1241 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1243 if (!fs->destructive()) {
1244 if (fs->empty() && !fs->used()) {
1249 child->add_child_nocopy (siter->second->get_state());
1254 child = node->add_child ("Regions");
1257 Glib::Threads::Mutex::Lock rl (region_lock);
1258 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1259 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1260 boost::shared_ptr<Region> r = i->second;
1261 /* only store regions not attached to playlists */
1262 if (r->playlist() == 0) {
1263 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1264 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1266 child->add_child_nocopy (r->get_state ());
1271 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1273 if (!cassocs.empty()) {
1274 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1276 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1278 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1279 i->first->id().print (buf, sizeof (buf));
1280 can->add_property (X_("copy"), buf);
1281 i->second->id().print (buf, sizeof (buf));
1282 can->add_property (X_("original"), buf);
1283 ca->add_child_nocopy (*can);
1293 node->add_child_nocopy (_locations->get_state());
1296 Locations loc (*this);
1297 const bool was_dirty = dirty();
1298 // for a template, just create a new Locations, populate it
1299 // with the default start and end, and get the state for that.
1300 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1301 range->set (max_framepos, 0);
1303 XMLNode& locations_state = loc.get_state();
1305 if (ARDOUR::Profile->get_trx() && _locations) {
1306 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1307 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1308 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1309 locations_state.add_child_nocopy ((*i)->get_state ());
1313 node->add_child_nocopy (locations_state);
1315 /* adding a location above will have marked the session
1316 * dirty. This is an artifact, so fix it if the session wasn't
1321 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1325 child = node->add_child ("Bundles");
1327 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1328 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1329 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1331 child->add_child_nocopy (b->get_state());
1336 node->add_child_nocopy (_vca_manager->get_state());
1338 child = node->add_child ("Routes");
1340 boost::shared_ptr<RouteList> r = routes.reader ();
1342 RoutePublicOrderSorter cmp;
1343 RouteList public_order (*r);
1344 public_order.sort (cmp);
1346 /* the sort should have put the monitor out first */
1349 assert (_monitor_out == public_order.front());
1352 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1353 if (!(*i)->is_auditioner()) {
1355 child->add_child_nocopy ((*i)->get_state());
1357 child->add_child_nocopy ((*i)->get_template());
1363 playlists->add_state (node, full_state);
1365 child = node->add_child ("RouteGroups");
1366 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1367 child->add_child_nocopy ((*i)->get_state());
1371 XMLNode* gain_child = node->add_child ("Click");
1372 gain_child->add_child_nocopy (_click_io->state (full_state));
1373 gain_child->add_child_nocopy (_click_gain->state (full_state));
1377 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1378 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1382 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1383 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1386 node->add_child_nocopy (_speakers->get_state());
1387 node->add_child_nocopy (_tempo_map->get_state());
1388 node->add_child_nocopy (get_control_protocol_state());
1391 node->add_child_copy (*_extra_xml);
1395 Glib::Threads::Mutex::Lock lm (lua_lock);
1398 luabridge::LuaRef savedstate ((*_lua_save)());
1399 saved = savedstate.cast<std::string>();
1401 lua.collect_garbage ();
1404 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1405 std::string b64s (b64);
1408 XMLNode* script_node = new XMLNode (X_("Script"));
1409 script_node->add_property (X_("lua"), LUA_VERSION);
1410 script_node->add_content (b64s);
1411 node->add_child_nocopy (*script_node);
1418 Session::get_control_protocol_state ()
1420 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1421 return cpm.get_state();
1425 Session::set_state (const XMLNode& node, int version)
1430 XMLProperty const * prop;
1433 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1435 if (node.name() != X_("Session")) {
1436 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1440 if ((prop = node.property ("name")) != 0) {
1441 _name = prop->value ();
1444 if ((prop = node.property (X_("sample-rate"))) != 0) {
1446 _base_frame_rate = atoi (prop->value());
1447 _nominal_frame_rate = _base_frame_rate;
1449 assert (AudioEngine::instance()->running ());
1450 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1451 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1452 if (r.get_value_or (0)) {
1458 created_with = "unknown";
1459 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1460 if ((prop = child->property (X_("created-with"))) != 0) {
1461 created_with = prop->value ();
1465 setup_raid_path(_session_dir->root_path());
1467 if ((prop = node.property (X_("end-is-free"))) != 0) {
1468 _session_range_end_is_free = string_is_affirmative (prop->value());
1471 if ((prop = node.property (X_("id-counter"))) != 0) {
1473 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1474 ID::init_counter (x);
1476 /* old sessions used a timebased counter, so fake
1477 the startup ID counter based on a standard
1482 ID::init_counter (now);
1485 if ((prop = node.property (X_("name-counter"))) != 0) {
1486 init_name_id_counter (atoi (prop->value()));
1489 if ((prop = node.property (X_("event-counter"))) != 0) {
1490 Evoral::init_event_id_counter (atoi (prop->value()));
1493 if ((prop = node.property (X_("vca-counter"))) != 0) {
1495 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1496 VCA::set_next_vca_number (x);
1498 VCA::set_next_vca_number (1);
1501 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1502 _midi_ports->set_midi_port_states (child->children());
1505 IO::disable_connecting ();
1507 Stateful::save_extra_xml (node);
1509 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1510 load_options (*child);
1511 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1512 load_options (*child);
1514 error << _("Session: XML state has no options section") << endmsg;
1517 if (version >= 3000) {
1518 if ((child = find_named_node (node, "Metadata")) == 0) {
1519 warning << _("Session: XML state has no metadata section") << endmsg;
1520 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1525 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1526 _speakers->set_state (*child, version);
1529 if ((child = find_named_node (node, "Sources")) == 0) {
1530 error << _("Session: XML state has no sources section") << endmsg;
1532 } else if (load_sources (*child)) {
1536 if ((child = find_named_node (node, "TempoMap")) == 0) {
1537 error << _("Session: XML state has no Tempo Map section") << endmsg;
1539 } else if (_tempo_map->set_state (*child, version)) {
1543 if ((child = find_named_node (node, "Locations")) == 0) {
1544 error << _("Session: XML state has no locations section") << endmsg;
1546 } else if (_locations->set_state (*child, version)) {
1550 locations_changed ();
1552 if (_session_range_location) {
1553 AudioFileSource::set_header_position_offset (_session_range_location->start());
1556 if ((child = find_named_node (node, "Regions")) == 0) {
1557 error << _("Session: XML state has no Regions section") << endmsg;
1559 } else if (load_regions (*child)) {
1563 if ((child = find_named_node (node, "Playlists")) == 0) {
1564 error << _("Session: XML state has no playlists section") << endmsg;
1566 } else if (playlists->load (*this, *child)) {
1570 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1572 } else if (playlists->load_unused (*this, *child)) {
1576 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1577 if (load_compounds (*child)) {
1582 if (version >= 3000) {
1583 if ((child = find_named_node (node, "Bundles")) == 0) {
1584 warning << _("Session: XML state has no bundles section") << endmsg;
1587 /* We can't load Bundles yet as they need to be able
1588 to convert from port names to Port objects, which can't happen until
1590 _bundle_xml_node = new XMLNode (*child);
1594 if (version < 3000) {
1595 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1596 error << _("Session: XML state has no diskstreams section") << endmsg;
1598 } else if (load_diskstreams_2X (*child, version)) {
1603 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1604 _vca_manager->set_state (*child, version);
1607 if ((child = find_named_node (node, "Routes")) == 0) {
1608 error << _("Session: XML state has no routes section") << endmsg;
1610 } else if (load_routes (*child, version)) {
1614 /* Now that we have Routes and masters loaded, connect them if appropriate */
1616 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1618 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1619 _diskstreams_2X.clear ();
1621 if (version >= 3000) {
1623 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1624 error << _("Session: XML state has no route groups section") << endmsg;
1626 } else if (load_route_groups (*child, version)) {
1630 } else if (version < 3000) {
1632 if ((child = find_named_node (node, "EditGroups")) == 0) {
1633 error << _("Session: XML state has no edit groups section") << endmsg;
1635 } else if (load_route_groups (*child, version)) {
1639 if ((child = find_named_node (node, "MixGroups")) == 0) {
1640 error << _("Session: XML state has no mix groups section") << endmsg;
1642 } else if (load_route_groups (*child, version)) {
1647 if ((child = find_named_node (node, "Click")) == 0) {
1648 warning << _("Session: XML state has no click section") << endmsg;
1649 } else if (_click_io) {
1650 setup_click_state (&node);
1653 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1654 ControlProtocolManager::instance().set_state (*child, version);
1657 if ((child = find_named_node (node, "Script"))) {
1658 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1659 if (!(*n)->is_content ()) { continue; }
1661 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1663 Glib::Threads::Mutex::Lock lm (lua_lock);
1664 (*_lua_load)(std::string ((const char*)buf, size));
1665 } catch (luabridge::LuaException const& e) {
1666 cerr << "LuaException:" << e.what () << endl;
1672 update_route_record_state ();
1674 /* here beginneth the second phase ... */
1675 set_snapshot_name (_current_snapshot_name);
1677 StateReady (); /* EMIT SIGNAL */
1690 Session::load_routes (const XMLNode& node, int version)
1693 XMLNodeConstIterator niter;
1694 RouteList new_routes;
1696 nlist = node.children();
1700 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1702 boost::shared_ptr<Route> route;
1703 if (version < 3000) {
1704 route = XMLRouteFactory_2X (**niter, version);
1706 route = XMLRouteFactory (**niter, version);
1710 error << _("Session: cannot create Route from XML description.") << endmsg;
1714 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1716 new_routes.push_back (route);
1719 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1721 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1723 BootMessage (_("Finished adding tracks/busses"));
1728 boost::shared_ptr<Route>
1729 Session::XMLRouteFactory (const XMLNode& node, int version)
1731 boost::shared_ptr<Route> ret;
1733 if (node.name() != "Route") {
1737 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1739 DataType type = DataType::AUDIO;
1740 XMLProperty const * prop = node.property("default-type");
1743 type = DataType (prop->value());
1746 assert (type != DataType::NIL);
1750 boost::shared_ptr<Track> track;
1752 if (type == DataType::AUDIO) {
1753 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1755 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1758 if (track->init()) {
1762 if (track->set_state (node, version)) {
1766 BOOST_MARK_TRACK (track);
1770 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1771 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1773 if (r->init () == 0 && r->set_state (node, version) == 0) {
1774 BOOST_MARK_ROUTE (r);
1782 boost::shared_ptr<Route>
1783 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1785 boost::shared_ptr<Route> ret;
1787 if (node.name() != "Route") {
1791 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1793 ds_prop = node.property (X_("diskstream"));
1796 DataType type = DataType::AUDIO;
1797 XMLProperty const * prop = node.property("default-type");
1800 type = DataType (prop->value());
1803 assert (type != DataType::NIL);
1807 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1808 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1812 if (i == _diskstreams_2X.end()) {
1813 error << _("Could not find diskstream for route") << endmsg;
1814 return boost::shared_ptr<Route> ();
1817 boost::shared_ptr<Track> track;
1819 if (type == DataType::AUDIO) {
1820 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1822 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1825 if (track->init()) {
1829 if (track->set_state (node, version)) {
1833 track->set_diskstream (*i);
1835 BOOST_MARK_TRACK (track);
1839 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1840 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1842 if (r->init () == 0 && r->set_state (node, version) == 0) {
1843 BOOST_MARK_ROUTE (r);
1852 Session::load_regions (const XMLNode& node)
1855 XMLNodeConstIterator niter;
1856 boost::shared_ptr<Region> region;
1858 nlist = node.children();
1862 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1863 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1864 error << _("Session: cannot create Region from XML description.");
1865 XMLProperty const * name = (**niter).property("name");
1868 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1879 Session::load_compounds (const XMLNode& node)
1881 XMLNodeList calist = node.children();
1882 XMLNodeConstIterator caiter;
1883 XMLProperty const * caprop;
1885 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1886 XMLNode* ca = *caiter;
1890 if ((caprop = ca->property (X_("original"))) == 0) {
1893 orig_id = caprop->value();
1895 if ((caprop = ca->property (X_("copy"))) == 0) {
1898 copy_id = caprop->value();
1900 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1901 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1903 if (!orig || !copy) {
1904 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1910 RegionFactory::add_compound_association (orig, copy);
1917 Session::load_nested_sources (const XMLNode& node)
1920 XMLNodeConstIterator niter;
1922 nlist = node.children();
1924 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1925 if ((*niter)->name() == "Source") {
1927 /* it may already exist, so don't recreate it unnecessarily
1930 XMLProperty const * prop = (*niter)->property (X_("id"));
1932 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1936 ID source_id (prop->value());
1938 if (!source_by_id (source_id)) {
1941 SourceFactory::create (*this, **niter, true);
1943 catch (failed_constructor& err) {
1944 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1951 boost::shared_ptr<Region>
1952 Session::XMLRegionFactory (const XMLNode& node, bool full)
1954 XMLProperty const * type = node.property("type");
1958 const XMLNodeList& nlist = node.children();
1960 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1961 XMLNode *child = (*niter);
1962 if (child->name() == "NestedSource") {
1963 load_nested_sources (*child);
1967 if (!type || type->value() == "audio") {
1968 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1969 } else if (type->value() == "midi") {
1970 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1973 } catch (failed_constructor& err) {
1974 return boost::shared_ptr<Region> ();
1977 return boost::shared_ptr<Region> ();
1980 boost::shared_ptr<AudioRegion>
1981 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1983 XMLProperty const * prop;
1984 boost::shared_ptr<Source> source;
1985 boost::shared_ptr<AudioSource> as;
1987 SourceList master_sources;
1988 uint32_t nchans = 1;
1991 if (node.name() != X_("Region")) {
1992 return boost::shared_ptr<AudioRegion>();
1995 if ((prop = node.property (X_("channels"))) != 0) {
1996 nchans = atoi (prop->value().c_str());
1999 if ((prop = node.property ("name")) == 0) {
2000 cerr << "no name for this region\n";
2004 if ((prop = node.property (X_("source-0"))) == 0) {
2005 if ((prop = node.property ("source")) == 0) {
2006 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2007 return boost::shared_ptr<AudioRegion>();
2011 PBD::ID s_id (prop->value());
2013 if ((source = source_by_id (s_id)) == 0) {
2014 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2015 return boost::shared_ptr<AudioRegion>();
2018 as = boost::dynamic_pointer_cast<AudioSource>(source);
2020 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2021 return boost::shared_ptr<AudioRegion>();
2024 sources.push_back (as);
2026 /* pickup other channels */
2028 for (uint32_t n=1; n < nchans; ++n) {
2029 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2030 if ((prop = node.property (buf)) != 0) {
2032 PBD::ID id2 (prop->value());
2034 if ((source = source_by_id (id2)) == 0) {
2035 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2036 return boost::shared_ptr<AudioRegion>();
2039 as = boost::dynamic_pointer_cast<AudioSource>(source);
2041 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2042 return boost::shared_ptr<AudioRegion>();
2044 sources.push_back (as);
2048 for (uint32_t n = 0; n < nchans; ++n) {
2049 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2050 if ((prop = node.property (buf)) != 0) {
2052 PBD::ID id2 (prop->value());
2054 if ((source = source_by_id (id2)) == 0) {
2055 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2056 return boost::shared_ptr<AudioRegion>();
2059 as = boost::dynamic_pointer_cast<AudioSource>(source);
2061 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2062 return boost::shared_ptr<AudioRegion>();
2064 master_sources.push_back (as);
2069 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2071 /* a final detail: this is the one and only place that we know how long missing files are */
2073 if (region->whole_file()) {
2074 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2075 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2077 sfp->set_length (region->length());
2082 if (!master_sources.empty()) {
2083 if (master_sources.size() != nchans) {
2084 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2086 region->set_master_sources (master_sources);
2094 catch (failed_constructor& err) {
2095 return boost::shared_ptr<AudioRegion>();
2099 boost::shared_ptr<MidiRegion>
2100 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2102 XMLProperty const * prop;
2103 boost::shared_ptr<Source> source;
2104 boost::shared_ptr<MidiSource> ms;
2107 if (node.name() != X_("Region")) {
2108 return boost::shared_ptr<MidiRegion>();
2111 if ((prop = node.property ("name")) == 0) {
2112 cerr << "no name for this region\n";
2116 if ((prop = node.property (X_("source-0"))) == 0) {
2117 if ((prop = node.property ("source")) == 0) {
2118 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2119 return boost::shared_ptr<MidiRegion>();
2123 PBD::ID s_id (prop->value());
2125 if ((source = source_by_id (s_id)) == 0) {
2126 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2127 return boost::shared_ptr<MidiRegion>();
2130 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2132 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2133 return boost::shared_ptr<MidiRegion>();
2136 sources.push_back (ms);
2139 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2140 /* a final detail: this is the one and only place that we know how long missing files are */
2142 if (region->whole_file()) {
2143 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2144 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2146 sfp->set_length (region->length());
2154 catch (failed_constructor& err) {
2155 return boost::shared_ptr<MidiRegion>();
2160 Session::get_sources_as_xml ()
2163 XMLNode* node = new XMLNode (X_("Sources"));
2164 Glib::Threads::Mutex::Lock lm (source_lock);
2166 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2167 node->add_child_nocopy (i->second->get_state());
2174 Session::reset_write_sources (bool mark_write_complete, bool force)
2176 boost::shared_ptr<RouteList> rl = routes.reader();
2177 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2178 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2180 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2181 tr->reset_write_sources(mark_write_complete, force);
2182 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2188 Session::load_sources (const XMLNode& node)
2191 XMLNodeConstIterator niter;
2192 /* don't need this but it stops some
2193 * versions of gcc complaining about
2194 * discarded return values.
2196 boost::shared_ptr<Source> source;
2198 nlist = node.children();
2202 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2203 #ifdef PLATFORM_WINDOWS
2209 #ifdef PLATFORM_WINDOWS
2210 // do not show "insert media" popups (files embedded from removable media).
2211 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2213 if ((source = XMLSourceFactory (**niter)) == 0) {
2214 error << _("Session: cannot create Source from XML description.") << endmsg;
2216 #ifdef PLATFORM_WINDOWS
2217 SetErrorMode(old_mode);
2220 } catch (MissingSource& err) {
2221 #ifdef PLATFORM_WINDOWS
2222 SetErrorMode(old_mode);
2227 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2228 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2229 PROGRAM_NAME) << endmsg;
2233 if (!no_questions_about_missing_files) {
2234 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2239 switch (user_choice) {
2241 /* user added a new search location, so try again */
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 /* never mark session dirty during loading */
3508 if (_state_of_the_state & Loading) {
3512 bool was_dirty = dirty();
3514 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3517 DirtyChanged(); /* EMIT SIGNAL */
3522 Session::set_clean ()
3524 bool was_dirty = dirty();
3526 _state_of_the_state = Clean;
3529 DirtyChanged(); /* EMIT SIGNAL */
3534 Session::set_deletion_in_progress ()
3536 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3540 Session::clear_deletion_in_progress ()
3542 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3546 Session::add_controllable (boost::shared_ptr<Controllable> c)
3548 /* this adds a controllable to the list managed by the Session.
3549 this is a subset of those managed by the Controllable class
3550 itself, and represents the only ones whose state will be saved
3551 as part of the session.
3554 Glib::Threads::Mutex::Lock lm (controllables_lock);
3555 controllables.insert (c);
3558 struct null_deleter { void operator()(void const *) const {} };
3561 Session::remove_controllable (Controllable* c)
3563 if (_state_of_the_state & Deletion) {
3567 Glib::Threads::Mutex::Lock lm (controllables_lock);
3569 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3571 if (x != controllables.end()) {
3572 controllables.erase (x);
3576 boost::shared_ptr<Controllable>
3577 Session::controllable_by_id (const PBD::ID& id)
3579 Glib::Threads::Mutex::Lock lm (controllables_lock);
3581 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3582 if ((*i)->id() == id) {
3587 return boost::shared_ptr<Controllable>();
3590 boost::shared_ptr<Controllable>
3591 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3593 boost::shared_ptr<Controllable> c;
3594 boost::shared_ptr<Stripable> s;
3595 boost::shared_ptr<Route> r;
3597 switch (desc.top_level_type()) {
3598 case ControllableDescriptor::NamedRoute:
3600 std::string str = desc.top_level_name();
3602 if (str == "Master" || str == "master") {
3604 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3606 } else if (str == "auditioner") {
3609 s = route_by_name (desc.top_level_name());
3615 case ControllableDescriptor::PresentationOrderRoute:
3616 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3619 case ControllableDescriptor::PresentationOrderTrack:
3620 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3623 case ControllableDescriptor::PresentationOrderBus:
3624 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3627 case ControllableDescriptor::PresentationOrderVCA:
3628 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3631 case ControllableDescriptor::SelectionCount:
3632 s = route_by_selected_count (desc.selection_id());
3640 r = boost::dynamic_pointer_cast<Route> (s);
3642 switch (desc.subtype()) {
3643 case ControllableDescriptor::Gain:
3644 c = s->gain_control ();
3647 case ControllableDescriptor::Trim:
3648 c = s->trim_control ();
3651 case ControllableDescriptor::Solo:
3652 c = s->solo_control();
3655 case ControllableDescriptor::Mute:
3656 c = s->mute_control();
3659 case ControllableDescriptor::Recenable:
3660 c = s->rec_enable_control ();
3663 case ControllableDescriptor::PanDirection:
3664 c = s->pan_azimuth_control();
3667 case ControllableDescriptor::PanWidth:
3668 c = s->pan_width_control();
3671 case ControllableDescriptor::PanElevation:
3672 c = s->pan_elevation_control();
3675 case ControllableDescriptor::Balance:
3676 /* XXX simple pan control */
3679 case ControllableDescriptor::PluginParameter:
3681 uint32_t plugin = desc.target (0);
3682 uint32_t parameter_index = desc.target (1);
3684 /* revert to zero based counting */
3690 if (parameter_index > 0) {
3698 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3701 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3702 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3707 case ControllableDescriptor::SendGain: {
3708 uint32_t send = desc.target (0);
3715 c = r->send_level_controllable (send);
3720 /* relax and return a null pointer */
3728 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3731 Stateful::add_instant_xml (node, _path);
3734 if (write_to_config) {
3735 Config->add_instant_xml (node);
3740 Session::instant_xml (const string& node_name)
3742 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3743 if (get_disable_all_loaded_plugins ()) {
3747 return Stateful::instant_xml (node_name, _path);
3751 Session::save_history (string snapshot_name)
3759 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3760 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3764 if (snapshot_name.empty()) {
3765 snapshot_name = _current_snapshot_name;
3768 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3769 const string backup_filename = history_filename + backup_suffix;
3770 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3771 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3773 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3774 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3775 error << _("could not backup old history file, current history not saved") << endmsg;
3780 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3782 if (!tree.write (xml_path))
3784 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3786 if (g_remove (xml_path.c_str()) != 0) {
3787 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3788 xml_path, g_strerror (errno)) << endmsg;
3790 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3791 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3792 backup_path, g_strerror (errno)) << endmsg;
3802 Session::restore_history (string snapshot_name)
3806 if (snapshot_name.empty()) {
3807 snapshot_name = _current_snapshot_name;
3810 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3811 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3813 info << "Loading history from " << xml_path << endmsg;
3815 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3816 info << string_compose (_("%1: no history file \"%2\" for this session."),
3817 _name, xml_path) << endmsg;
3821 if (!tree.read (xml_path)) {
3822 error << string_compose (_("Could not understand session history file \"%1\""),
3823 xml_path) << endmsg;
3830 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3833 UndoTransaction* ut = new UndoTransaction ();
3836 ut->set_name(t->property("name")->value());
3837 stringstream ss(t->property("tv-sec")->value());
3839 ss.str(t->property("tv-usec")->value());
3841 ut->set_timestamp(tv);
3843 for (XMLNodeConstIterator child_it = t->children().begin();
3844 child_it != t->children().end(); child_it++)
3846 XMLNode *n = *child_it;
3849 if (n->name() == "MementoCommand" ||
3850 n->name() == "MementoUndoCommand" ||
3851 n->name() == "MementoRedoCommand") {
3853 if ((c = memento_command_factory(n))) {
3857 } else if (n->name() == "NoteDiffCommand") {
3858 PBD::ID id (n->property("midi-source")->value());
3859 boost::shared_ptr<MidiSource> midi_source =
3860 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3862 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3864 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3867 } else if (n->name() == "SysExDiffCommand") {
3869 PBD::ID id (n->property("midi-source")->value());
3870 boost::shared_ptr<MidiSource> midi_source =
3871 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3873 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3875 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3878 } else if (n->name() == "PatchChangeDiffCommand") {
3880 PBD::ID id (n->property("midi-source")->value());
3881 boost::shared_ptr<MidiSource> midi_source =
3882 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3884 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3886 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3889 } else if (n->name() == "StatefulDiffCommand") {
3890 if ((c = stateful_diff_command_factory (n))) {
3891 ut->add_command (c);
3894 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3905 Session::config_changed (std::string p, bool ours)
3911 if (p == "seamless-loop") {
3913 } else if (p == "rf-speed") {
3915 } else if (p == "auto-loop") {
3917 } else if (p == "session-monitoring") {
3919 } else if (p == "auto-input") {
3921 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3922 /* auto-input only makes a difference if we're rolling */
3923 set_track_monitor_input_status (!config.get_auto_input());
3926 } else if (p == "punch-in") {
3930 if ((location = _locations->auto_punch_location()) != 0) {
3932 if (config.get_punch_in ()) {
3933 replace_event (SessionEvent::PunchIn, location->start());
3935 remove_event (location->start(), SessionEvent::PunchIn);
3939 } else if (p == "punch-out") {
3943 if ((location = _locations->auto_punch_location()) != 0) {
3945 if (config.get_punch_out()) {
3946 replace_event (SessionEvent::PunchOut, location->end());
3948 clear_events (SessionEvent::PunchOut);
3952 } else if (p == "edit-mode") {
3954 Glib::Threads::Mutex::Lock lm (playlists->lock);
3956 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3957 (*i)->set_edit_mode (Config->get_edit_mode ());
3960 } else if (p == "use-video-sync") {
3962 waiting_for_sync_offset = config.get_use_video_sync();
3964 } else if (p == "mmc-control") {
3966 //poke_midi_thread ();
3968 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3970 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3972 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3974 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3976 } else if (p == "midi-control") {
3978 //poke_midi_thread ();
3980 } else if (p == "raid-path") {
3982 setup_raid_path (config.get_raid_path());
3984 } else if (p == "timecode-format") {
3988 } else if (p == "video-pullup") {
3992 } else if (p == "seamless-loop") {
3994 if (play_loop && transport_rolling()) {
3995 // to reset diskstreams etc
3996 request_play_loop (true);
3999 } else if (p == "rf-speed") {
4001 cumulative_rf_motion = 0;
4004 } else if (p == "click-sound") {
4006 setup_click_sounds (1);
4008 } else if (p == "click-emphasis-sound") {
4010 setup_click_sounds (-1);
4012 } else if (p == "clicking") {
4014 if (Config->get_clicking()) {
4015 if (_click_io && click_data) { // don't require emphasis data
4022 } else if (p == "click-gain") {
4025 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4028 } else if (p == "send-mtc") {
4030 if (Config->get_send_mtc ()) {
4031 /* mark us ready to send */
4032 next_quarter_frame_to_send = 0;
4035 } else if (p == "send-mmc") {
4037 _mmc->enable_send (Config->get_send_mmc ());
4039 } else if (p == "jack-time-master") {
4041 engine().reset_timebase ();
4043 } else if (p == "native-file-header-format") {
4045 if (!first_file_header_format_reset) {
4046 reset_native_file_format ();
4049 first_file_header_format_reset = false;
4051 } else if (p == "native-file-data-format") {
4053 if (!first_file_data_format_reset) {
4054 reset_native_file_format ();
4057 first_file_data_format_reset = false;
4059 } else if (p == "external-sync") {
4060 if (!config.get_external_sync()) {
4061 drop_sync_source ();
4063 switch_to_sync_source (Config->get_sync_source());
4065 } else if (p == "denormal-model") {
4067 } else if (p == "history-depth") {
4068 set_history_depth (Config->get_history_depth());
4069 } else if (p == "remote-model") {
4070 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4073 } else if (p == "initial-program-change") {
4075 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4078 buf[0] = MIDI::program; // channel zero by default
4079 buf[1] = (Config->get_initial_program_change() & 0x7f);
4081 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4083 } else if (p == "solo-mute-override") {
4084 // catch_up_on_solo_mute_override ();
4085 } else if (p == "listen-position" || p == "pfl-position") {
4086 listen_position_changed ();
4087 } else if (p == "solo-control-is-listen-control") {
4088 solo_control_mode_changed ();
4089 } else if (p == "solo-mute-gain") {
4090 _solo_cut_control->Changed (true, Controllable::NoGroup);
4091 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4092 last_timecode_valid = false;
4093 } else if (p == "playback-buffer-seconds") {
4094 AudioSource::allocate_working_buffers (frame_rate());
4095 } else if (p == "ltc-source-port") {
4096 reconnect_ltc_input ();
4097 } else if (p == "ltc-sink-port") {
4098 reconnect_ltc_output ();
4099 } else if (p == "timecode-generator-offset") {
4100 ltc_tx_parse_offset();
4101 } else if (p == "auto-return-target-list") {
4102 follow_playhead_priority ();
4109 Session::set_history_depth (uint32_t d)
4111 _history.set_depth (d);
4115 Session::load_diskstreams_2X (XMLNode const & node, int)
4118 XMLNodeConstIterator citer;
4120 clist = node.children();
4122 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4125 /* diskstreams added automatically by DiskstreamCreated handler */
4126 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4127 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4128 _diskstreams_2X.push_back (dsp);
4130 error << _("Session: unknown diskstream type in XML") << endmsg;
4134 catch (failed_constructor& err) {
4135 error << _("Session: could not load diskstream via XML state") << endmsg;
4143 /** Connect things to the MMC object */
4145 Session::setup_midi_machine_control ()
4147 _mmc = new MIDI::MachineControl;
4149 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4150 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4152 if (!async_out || !async_out) {
4156 /* XXXX argh, passing raw pointers back into libmidi++ */
4158 MIDI::Port* mmc_in = async_in.get();
4159 MIDI::Port* mmc_out = async_out.get();
4161 _mmc->set_ports (mmc_in, mmc_out);
4163 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4164 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4165 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4166 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4167 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4168 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4169 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4170 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4171 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4172 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4173 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4174 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4175 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4177 /* also handle MIDI SPP because its so common */
4179 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4180 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4181 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4184 boost::shared_ptr<Controllable>
4185 Session::solo_cut_control() const
4187 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4188 controls in Ardour that currently get presented to the user in the GUI that require
4189 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4191 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4192 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4196 return _solo_cut_control;
4200 Session::save_snapshot_name (const std::string & n)
4202 /* assure Stateful::_instant_xml is loaded
4203 * add_instant_xml() only adds to existing data and defaults
4204 * to use an empty Tree otherwise
4206 instant_xml ("LastUsedSnapshot");
4208 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4209 last_used_snapshot->add_property ("name", string(n));
4210 add_instant_xml (*last_used_snapshot, false);
4214 Session::set_snapshot_name (const std::string & n)
4216 _current_snapshot_name = n;
4217 save_snapshot_name (n);
4221 Session::rename (const std::string& new_name)
4223 string legal_name = legalize_for_path (new_name);
4229 string const old_sources_root = _session_dir->sources_root();
4231 if (!_writable || (_state_of_the_state & CannotSave)) {
4232 error << _("Cannot rename read-only session.") << endmsg;
4233 return 0; // don't show "messed up" warning
4235 if (record_status() == Recording) {
4236 error << _("Cannot rename session while recording") << endmsg;
4237 return 0; // don't show "messed up" warning
4240 StateProtector stp (this);
4245 * interchange subdirectory
4249 * Backup files are left unchanged and not renamed.
4252 /* Windows requires that we close all files before attempting the
4253 * rename. This works on other platforms, but isn't necessary there.
4254 * Leave it in place for all platforms though, since it may help
4255 * catch issues that could arise if the way Source files work ever
4256 * change (since most developers are not using Windows).
4259 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4260 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4266 /* pass one: not 100% safe check that the new directory names don't
4270 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4274 /* this is a stupid hack because Glib::path_get_dirname() is
4275 * lexical-only, and so passing it /a/b/c/ gives a different
4276 * result than passing it /a/b/c ...
4279 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4280 oldstr = oldstr.substr (0, oldstr.length() - 1);
4283 string base = Glib::path_get_dirname (oldstr);
4285 newstr = Glib::build_filename (base, legal_name);
4287 cerr << "Looking for " << newstr << endl;
4289 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4290 cerr << " exists\n";
4299 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4305 /* this is a stupid hack because Glib::path_get_dirname() is
4306 * lexical-only, and so passing it /a/b/c/ gives a different
4307 * result than passing it /a/b/c ...
4310 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4311 oldstr = oldstr.substr (0, oldstr.length() - 1);
4314 string base = Glib::path_get_dirname (oldstr);
4315 newstr = Glib::build_filename (base, legal_name);
4317 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4319 cerr << "Rename " << oldstr << " => " << newstr << endl;
4320 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4321 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4322 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4326 /* Reset path in "session dirs" */
4331 /* reset primary SessionDirectory object */
4334 (*_session_dir) = newstr;
4339 /* now rename directory below session_dir/interchange */
4341 string old_interchange_dir;
4342 string new_interchange_dir;
4344 /* use newstr here because we renamed the path
4345 * (folder/directory) that used to be oldstr to newstr above
4348 v.push_back (newstr);
4349 v.push_back (interchange_dir_name);
4350 v.push_back (Glib::path_get_basename (oldstr));
4352 old_interchange_dir = Glib::build_filename (v);
4355 v.push_back (newstr);
4356 v.push_back (interchange_dir_name);
4357 v.push_back (legal_name);
4359 new_interchange_dir = Glib::build_filename (v);
4361 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4363 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4364 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4365 old_interchange_dir, new_interchange_dir,
4368 error << string_compose (_("renaming %s as %2 failed (%3)"),
4369 old_interchange_dir, new_interchange_dir,
4378 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4379 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4381 cerr << "Rename " << oldstr << " => " << newstr << endl;
4383 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4384 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4385 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4391 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4393 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4394 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4396 cerr << "Rename " << oldstr << " => " << newstr << endl;
4398 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4399 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4400 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4405 /* remove old name from recent sessions */
4406 remove_recent_sessions (_path);
4409 /* update file source paths */
4411 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4412 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4414 string p = fs->path ();
4415 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4417 SourceFactory::setup_peakfile(i->second, true);
4421 set_snapshot_name (new_name);
4426 /* save state again to get everything just right */
4428 save_state (_current_snapshot_name);
4430 /* add to recent sessions */
4432 store_recent_sessions (new_name, _path);
4438 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4440 bool found_sr = false;
4441 bool found_data_format = false;
4442 program_version = "";
4444 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4448 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4452 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4455 xmlFreeParserCtxt(ctxt);
4459 xmlNodePtr node = xmlDocGetRootElement(doc);
4462 xmlFreeParserCtxt(ctxt);
4470 for (attr = node->properties; attr; attr = attr->next) {
4471 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4472 sample_rate = atoi ((char*)attr->children->content);
4477 node = node->children;
4478 while (node != NULL) {
4479 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4480 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4482 program_version = string ((const char*)val);
4483 size_t sep = program_version.find_first_of("-");
4484 if (sep != string::npos) {
4485 program_version = program_version.substr (0, sep);
4490 if (strcmp((const char*) node->name, "Config")) {
4494 for (node = node->children; node; node = node->next) {
4495 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4496 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4498 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4500 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4502 found_data_format = true;
4512 xmlFreeParserCtxt(ctxt);
4515 return !(found_sr && found_data_format); // zero if they are both found
4519 Session::get_snapshot_from_instant (const std::string& session_dir)
4521 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4523 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4528 if (!tree.read (instant_xml_path)) {
4532 XMLProperty const * prop;
4533 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4534 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4535 return prop->value();
4541 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4542 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4545 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4549 SourcePathMap source_path_map;
4551 boost::shared_ptr<AudioFileSource> afs;
4556 Glib::Threads::Mutex::Lock lm (source_lock);
4558 cerr << " total sources = " << sources.size();
4560 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4561 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4567 if (fs->within_session()) {
4571 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4572 source_path_map[fs->path()].push_back (fs);
4574 SeveralFileSources v;
4576 source_path_map.insert (make_pair (fs->path(), v));
4582 cerr << " fsources = " << total << endl;
4584 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4586 /* tell caller where we are */
4588 string old_path = i->first;
4590 callback (n, total, old_path);
4592 cerr << old_path << endl;
4596 switch (i->second.front()->type()) {
4597 case DataType::AUDIO:
4598 new_path = new_audio_source_path_for_embedded (old_path);
4601 case DataType::MIDI:
4602 /* XXX not implemented yet */
4606 if (new_path.empty()) {
4610 cerr << "Move " << old_path << " => " << new_path << endl;
4612 if (!copy_file (old_path, new_path)) {
4613 cerr << "failed !\n";
4617 /* make sure we stop looking in the external
4618 dir/folder. Remember, this is an all-or-nothing
4619 operations, it doesn't merge just some files.
4621 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4623 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4624 (*f)->set_path (new_path);
4629 save_state ("", false, false);
4635 bool accept_all_files (string const &, void *)
4641 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4643 /* 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.
4648 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4650 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4652 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4654 v.push_back (new_session_folder); /* full path */
4655 v.push_back (interchange_dir_name);
4656 v.push_back (new_session_path); /* just one directory/folder */
4657 v.push_back (typedir);
4658 v.push_back (Glib::path_get_basename (old_path));
4660 return Glib::build_filename (v);
4664 Session::save_as (SaveAs& saveas)
4666 vector<string> files;
4667 string current_folder = Glib::path_get_dirname (_path);
4668 string new_folder = legalize_for_path (saveas.new_name);
4669 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4670 int64_t total_bytes = 0;
4674 int32_t internal_file_cnt = 0;
4676 vector<string> do_not_copy_extensions;
4677 do_not_copy_extensions.push_back (statefile_suffix);
4678 do_not_copy_extensions.push_back (pending_suffix);
4679 do_not_copy_extensions.push_back (backup_suffix);
4680 do_not_copy_extensions.push_back (temp_suffix);
4681 do_not_copy_extensions.push_back (history_suffix);
4683 /* get total size */
4685 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4687 /* need to clear this because
4688 * find_files_matching_filter() is cumulative
4693 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4695 all += files.size();
4697 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4699 g_stat ((*i).c_str(), &gsb);
4700 total_bytes += gsb.st_size;
4704 /* save old values so we can switch back if we are not switching to the new session */
4706 string old_path = _path;
4707 string old_name = _name;
4708 string old_snapshot = _current_snapshot_name;
4709 string old_sd = _session_dir->root_path();
4710 vector<string> old_search_path[DataType::num_types];
4711 string old_config_search_path[DataType::num_types];
4713 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4714 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4715 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4716 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4718 /* switch session directory */
4720 (*_session_dir) = to_dir;
4722 /* create new tree */
4724 if (!_session_dir->create()) {
4725 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4730 /* copy all relevant files. Find each location in session_dirs,
4731 * and copy files from there to target.
4734 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4736 /* need to clear this because
4737 * find_files_matching_filter() is cumulative
4742 const size_t prefix_len = (*sd).path.size();
4744 /* Work just on the files within this session dir */
4746 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4748 /* add dir separator to protect against collisions with
4749 * track names (e.g. track named "audiofiles" or
4753 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4754 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4755 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4757 /* copy all the files. Handling is different for media files
4758 than others because of the *silly* subtree we have below the interchange
4759 folder. That really was a bad idea, but I'm not fixing it as part of
4760 implementing ::save_as().
4763 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4765 std::string from = *i;
4768 string filename = Glib::path_get_basename (from);
4769 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4770 if (filename == ".DS_STORE") {
4775 if (from.find (audiofile_dir_string) != string::npos) {
4777 /* audio file: only copy if asked */
4779 if (saveas.include_media && saveas.copy_media) {
4781 string to = make_new_media_path (*i, to_dir, new_folder);
4783 info << "media file copying from " << from << " to " << to << endmsg;
4785 if (!copy_file (from, to)) {
4786 throw Glib::FileError (Glib::FileError::IO_ERROR,
4787 string_compose(_("\ncopying \"%1\" failed !"), from));
4791 /* we found media files inside the session folder */
4793 internal_file_cnt++;
4795 } else if (from.find (midifile_dir_string) != string::npos) {
4797 /* midi file: always copy unless
4798 * creating an empty new session
4801 if (saveas.include_media) {
4803 string to = make_new_media_path (*i, to_dir, new_folder);
4805 info << "media file copying from " << from << " to " << to << endmsg;
4807 if (!copy_file (from, to)) {
4808 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4812 /* we found media files inside the session folder */
4814 internal_file_cnt++;
4816 } else if (from.find (analysis_dir_string) != string::npos) {
4818 /* make sure analysis dir exists in
4819 * new session folder, but we're not
4820 * copying analysis files here, see
4824 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4829 /* normal non-media file. Don't copy state, history, etc.
4832 bool do_copy = true;
4834 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4835 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4836 /* end of filename matches extension, do not copy file */
4842 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4843 /* don't copy peakfiles if
4844 * we're not copying media
4850 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4852 info << "attempting to make directory/folder " << to << endmsg;
4854 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4855 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4858 info << "attempting to copy " << from << " to " << to << endmsg;
4860 if (!copy_file (from, to)) {
4861 throw Glib::FileError (Glib::FileError::IO_ERROR,
4862 string_compose(_("\ncopying \"%1\" failed !"), from));
4867 /* measure file size even if we're not going to copy so that our Progress
4868 signals are correct, since we included these do-not-copy files
4869 in the computation of the total size and file count.
4873 g_stat (from.c_str(), &gsb);
4874 copied += gsb.st_size;
4877 double fraction = (double) copied / total_bytes;
4879 bool keep_going = true;
4881 if (saveas.copy_media) {
4883 /* no need or expectation of this if
4884 * media is not being copied, because
4885 * it will be fast(ish).
4888 /* tell someone "X percent, file M of N"; M is one-based */
4890 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4898 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4904 /* copy optional folders, if any */
4906 string old = plugins_dir ();
4907 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4908 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4909 copy_files (old, newdir);
4912 old = externals_dir ();
4913 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4914 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4915 copy_files (old, newdir);
4918 old = automation_dir ();
4919 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4920 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4921 copy_files (old, newdir);
4924 if (saveas.include_media) {
4926 if (saveas.copy_media) {
4927 #ifndef PLATFORM_WINDOWS
4928 /* There are problems with analysis files on
4929 * Windows, because they used a colon in their
4930 * names as late as 4.0. Colons are not legal
4931 * under Windows even if NTFS allows them.
4933 * This is a tricky problem to solve so for
4934 * just don't copy these files. They will be
4935 * regenerated as-needed anyway, subject to the
4936 * existing issue that the filenames will be
4937 * rejected by Windows, which is a separate
4938 * problem (though related).
4941 /* only needed if we are copying media, since the
4942 * analysis data refers to media data
4945 old = analysis_dir ();
4946 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4947 string newdir = Glib::build_filename (to_dir, "analysis");
4948 copy_files (old, newdir);
4950 #endif /* PLATFORM_WINDOWS */
4955 set_snapshot_name (saveas.new_name);
4956 _name = saveas.new_name;
4958 if (saveas.include_media && !saveas.copy_media) {
4960 /* reset search paths of the new session (which we're pretending to be right now) to
4961 include the original session search path, so we can still find all audio.
4964 if (internal_file_cnt) {
4965 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4966 ensure_search_path_includes (*s, DataType::AUDIO);
4967 cerr << "be sure to include " << *s << " for audio" << endl;
4970 /* we do not do this for MIDI because we copy
4971 all MIDI files if saveas.include_media is
4977 bool was_dirty = dirty ();
4979 save_default_options ();
4981 if (saveas.copy_media && saveas.copy_external) {
4982 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4983 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4987 saveas.final_session_folder_name = _path;
4989 store_recent_sessions (_name, _path);
4991 if (!saveas.switch_to) {
4993 /* save the new state */
4995 save_state ("", false, false, !saveas.include_media);
4997 /* switch back to the way things were */
5001 set_snapshot_name (old_snapshot);
5003 (*_session_dir) = old_sd;
5009 if (internal_file_cnt) {
5010 /* reset these to their original values */
5011 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5012 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5017 /* prune session dirs, and update disk space statistics
5022 session_dirs.clear ();
5023 session_dirs.push_back (sp);
5024 refresh_disk_space ();
5026 /* ensure that all existing tracks reset their current capture source paths
5028 reset_write_sources (true, true);
5030 /* creating new write sources marks the session as
5031 dirty. If the new session is empty, then
5032 save_state() thinks we're saving a template and will
5033 not mark the session as clean. So do that here,
5034 before we save state.
5037 if (!saveas.include_media) {
5038 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5041 save_state ("", false, false, !saveas.include_media);
5043 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5044 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5047 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5048 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5054 if (fs->within_session()) {
5055 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5056 fs->set_path (newpath);
5061 } catch (Glib::FileError& e) {
5063 saveas.failure_message = e.what();
5065 /* recursively remove all the directories */
5067 remove_directory (to_dir);
5075 saveas.failure_message = _("unknown reason");
5077 /* recursively remove all the directories */
5079 remove_directory (to_dir);
5089 static void set_progress (Progress* p, size_t n, size_t t)
5091 p->set_progress (float (n) / float(t));
5095 Session::archive_session (const std::string& dest,
5096 const std::string& name,
5097 ArchiveEncode compress_audio,
5098 bool only_used_sources,
5101 if (dest.empty () || name.empty ()) {
5105 /* save current values */
5106 bool was_dirty = dirty ();
5107 string old_path = _path;
5108 string old_name = _name;
5109 string old_snapshot = _current_snapshot_name;
5110 string old_sd = _session_dir->root_path();
5111 string old_config_search_path[DataType::num_types];
5112 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5113 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5115 /* ensure that session-path is included in search-path */
5117 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5118 if ((*sd).path == old_path) {
5126 /* create temporary dir to save session to */
5127 #ifdef PLATFORM_WINDOWS
5128 char tmp[256] = "C:\\TEMP\\";
5129 GetTempPath (sizeof (tmp), tmp);
5131 char const* tmp = getenv("TMPDIR");
5136 if ((strlen (tmp) + 21) > 1024) {
5141 strcpy (tmptpl, tmp);
5142 strcat (tmptpl, "ardourarchive-XXXXXX");
5143 char* tmpdir = g_mkdtemp (tmptpl);
5149 std::string to_dir = std::string (tmpdir);
5151 /* switch session directory temporarily */
5152 (*_session_dir) = to_dir;
5154 if (!_session_dir->create()) {
5155 (*_session_dir) = old_sd;
5156 remove_directory (to_dir);
5160 /* prepare archive */
5161 string archive = Glib::build_filename (dest, name + ".tar.xz");
5163 PBD::ScopedConnectionList progress_connection;
5164 PBD::FileArchive ar (archive);
5166 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5169 /* collect files to archive */
5170 std::map<string,string> filemap;
5172 vector<string> do_not_copy_extensions;
5173 do_not_copy_extensions.push_back (statefile_suffix);
5174 do_not_copy_extensions.push_back (pending_suffix);
5175 do_not_copy_extensions.push_back (backup_suffix);
5176 do_not_copy_extensions.push_back (temp_suffix);
5177 do_not_copy_extensions.push_back (history_suffix);
5179 vector<string> blacklist_dirs;
5180 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5181 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5182 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5183 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5184 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5185 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5187 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5188 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5190 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5191 if (only_used_sources) {
5192 playlists->sync_all_regions_with_regions ();
5193 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5196 // collect audio sources for this session, calc total size for encoding
5197 // add option to only include *used* sources (see Session::cleanup_sources)
5198 size_t total_size = 0;
5200 Glib::Threads::Mutex::Lock lm (source_lock);
5201 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5202 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5203 if (!afs || afs->readable_length () == 0) {
5207 if (only_used_sources) {
5211 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5216 std::string from = afs->path();
5218 if (compress_audio != NO_ENCODE) {
5219 total_size += afs->readable_length ();
5221 if (afs->within_session()) {
5222 filemap[from] = make_new_media_path (from, name, name);
5224 filemap[from] = make_new_media_path (from, name, name);
5225 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5232 if (compress_audio != NO_ENCODE) {
5234 progress->set_progress (2); // set to "encoding"
5235 progress->set_progress (0);
5238 Glib::Threads::Mutex::Lock lm (source_lock);
5239 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5240 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5241 if (!afs || afs->readable_length () == 0) {
5245 if (only_used_sources) {
5249 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5254 orig_sources[afs] = afs->path();
5255 orig_gain[afs] = afs->gain();
5257 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5258 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5259 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5262 progress->descend ((float)afs->readable_length () / total_size);
5266 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5267 afs->replace_file (new_path);
5268 afs->set_gain (ns->gain(), true);
5271 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5275 progress->ascend ();
5281 progress->set_progress (-1); // set to "archiving"
5282 progress->set_progress (0);
5285 /* index files relevant for this session */
5286 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5287 vector<string> files;
5289 size_t prefix_len = (*sd).path.size();
5290 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5294 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5296 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5297 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5298 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5300 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5301 std::string from = *i;
5304 string filename = Glib::path_get_basename (from);
5305 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5306 if (filename == ".DS_STORE") {
5311 if (from.find (audiofile_dir_string) != string::npos) {
5313 } else if (from.find (midifile_dir_string) != string::npos) {
5314 filemap[from] = make_new_media_path (from, name, name);
5315 } else if (from.find (videofile_dir_string) != string::npos) {
5316 filemap[from] = make_new_media_path (from, name, name);
5318 bool do_copy = true;
5319 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5320 if (from.find (*v) != string::npos) {
5325 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5326 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5333 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5339 /* write session file */
5341 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5343 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5346 save_default_options ();
5348 size_t prefix_len = _path.size();
5349 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5353 /* collect session-state files */
5354 vector<string> files;
5355 do_not_copy_extensions.clear ();
5356 do_not_copy_extensions.push_back (history_suffix);
5358 blacklist_dirs.clear ();
5359 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5361 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5362 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5363 std::string from = *i;
5364 bool do_copy = true;
5365 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5366 if (from.find (*v) != string::npos) {
5371 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5372 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5378 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5382 /* restore original values */
5385 set_snapshot_name (old_snapshot);
5386 (*_session_dir) = old_sd;
5390 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5391 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5393 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5394 i->first->replace_file (i->second);
5396 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5397 i->first->set_gain (i->second, true);
5400 int rv = ar.create (filemap);
5401 remove_directory (to_dir);
5407 Session::undo (uint32_t n)
5409 if (actively_recording()) {
5417 Session::redo (uint32_t n)
5419 if (actively_recording()) {