2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/sndfilesource.h"
124 #include "ardour/source_factory.h"
125 #include "ardour/speakers.h"
126 #include "ardour/template_utils.h"
127 #include "ardour/tempo.h"
128 #include "ardour/ticker.h"
129 #include "ardour/types_convert.h"
130 #include "ardour/user_bundle.h"
131 #include "ardour/vca.h"
132 #include "ardour/vca_manager.h"
134 #include "control_protocol/control_protocol.h"
136 #include "LuaBridge/LuaBridge.h"
138 #include "pbd/i18n.h"
142 using namespace ARDOUR;
145 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
148 Session::pre_engine_init (string fullpath)
150 if (fullpath.empty()) {
152 throw failed_constructor();
155 /* discover canonical fullpath */
157 _path = canonical_path(fullpath);
160 if (Profile->get_trx() ) {
161 // Waves TracksLive has a usecase of session replacement with a new one.
162 // We should check session state file (<session_name>.ardour) existance
163 // to determine if the session is new or not
165 string full_session_name = Glib::build_filename( fullpath, _name );
166 full_session_name += statefile_suffix;
168 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 /* finish initialization that can't be done in a normal C++ constructor
177 timerclear (&last_mmc_step);
178 g_atomic_int_set (&processing_prohibited, 0);
179 g_atomic_int_set (&_record_status, Disabled);
180 g_atomic_int_set (&_playback_load, 100);
181 g_atomic_int_set (&_capture_load, 100);
183 _all_route_group->set_active (true, this);
184 interpolation.add_channel_to (0, 0);
186 if (config.get_use_video_sync()) {
187 waiting_for_sync_offset = true;
189 waiting_for_sync_offset = false;
192 last_rr_session_dir = session_dirs.begin();
194 set_history_depth (Config->get_history_depth());
196 /* default: assume simple stereo speaker configuration */
198 _speakers->setup_default_speakers (2);
200 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
201 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
202 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
203 add_controllable (_solo_cut_control);
205 /* These are all static "per-class" signals */
207 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
208 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
209 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
210 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
213 /* stop IO objects from doing stuff until we're ready for them */
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
220 Session::post_engine_init ()
222 BootMessage (_("Set block size and sample rate"));
224 set_block_size (_engine.samples_per_cycle());
225 set_frame_rate (_engine.sample_rate());
227 BootMessage (_("Using configuration"));
229 _midi_ports = new MidiPortManager;
231 MIDISceneChanger* msc;
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
237 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
240 setup_midi_machine_control ();
242 if (_butler->start_thread()) {
243 error << _("Butler did not start") << endmsg;
247 if (start_midi_thread ()) {
248 error << _("MIDI I/O thread did not start") << endmsg;
252 setup_click_sounds (0);
253 setup_midi_control ();
255 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
256 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
259 /* tempo map requires sample rate knowledge */
262 _tempo_map = new TempoMap (_current_frame_rate);
263 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
264 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 /* MidiClock requires a tempo map */
269 midi_clock = new MidiClockTicker ();
270 midi_clock->set_session (this);
272 /* crossfades require sample rate knowledge */
274 SndFileSource::setup_standard_crossfades (*this, frame_rate());
275 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
276 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
278 AudioDiskstream::allocate_working_buffers();
279 refresh_disk_space ();
281 /* we're finally ready to call set_state() ... all objects have
282 * been created, the engine is running.
286 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
287 error << _("Could not set session state from XML") << endmsg;
291 // set_state() will call setup_raid_path(), but if it's a new session we need
292 // to call setup_raid_path() here.
293 setup_raid_path (_path);
298 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
299 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
301 Config->map_parameters (ff);
302 config.map_parameters (ft);
303 _butler->map_parameters ();
305 /* Reset all panners */
307 Delivery::reset_panners ();
309 /* this will cause the CPM to instantiate any protocols that are in use
310 * (or mandatory), which will pass it this Session, and then call
311 * set_state() on each instantiated protocol to match stored state.
314 ControlProtocolManager::instance().set_session (this);
316 /* This must be done after the ControlProtocolManager set_session above,
317 as it will set states for ports which the ControlProtocolManager creates.
320 // XXX set state of MIDI::Port's
321 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
323 /* And this must be done after the MIDI::Manager::set_port_states as
324 * it will try to make connections whose details are loaded by set_port_states.
329 /* Let control protocols know that we are now all connected, so they
330 * could start talking to surfaces if they want to.
333 ControlProtocolManager::instance().midi_connectivity_established ();
335 if (_is_new && !no_auto_connect()) {
336 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
337 auto_connect_master_bus ();
340 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
342 /* update latencies */
344 initialize_latencies ();
346 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
347 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
348 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
350 } catch (AudioEngine::PortRegistrationFailure& err) {
351 /* handle this one in a different way than all others, so that its clear what happened */
352 error << err.what() << endmsg;
354 } catch (std::exception const & e) {
355 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
358 error << _("Unknown exception during session setup") << endmsg;
362 BootMessage (_("Reset Remote Controls"));
364 // send_full_time_code (0);
365 _engine.transport_locate (0);
367 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
368 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
370 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
373 /* initial program change will be delivered later; see ::config_changed() */
375 _state_of_the_state = Clean;
377 Port::set_connecting_blocked (false);
379 DirtyChanged (); /* EMIT SIGNAL */
383 } else if (state_was_pending) {
385 remove_pending_capture_state ();
386 state_was_pending = false;
389 /* Now, finally, we can fill the playback buffers */
391 BootMessage (_("Filling playback buffers"));
393 boost::shared_ptr<RouteList> rl = routes.reader();
394 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
395 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
396 if (trk && !trk->hidden()) {
397 trk->seek (_transport_frame, true);
405 Session::session_loaded ()
409 _state_of_the_state = Clean;
411 DirtyChanged (); /* EMIT SIGNAL */
415 } else if (state_was_pending) {
417 remove_pending_capture_state ();
418 state_was_pending = false;
421 /* Now, finally, we can fill the playback buffers */
423 BootMessage (_("Filling playback buffers"));
424 force_locate (_transport_frame, false);
428 Session::raid_path () const
430 Searchpath raid_search_path;
432 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
433 raid_search_path += (*i).path;
436 return raid_search_path.to_string ();
440 Session::setup_raid_path (string path)
449 session_dirs.clear ();
451 Searchpath search_path(path);
452 Searchpath sound_search_path;
453 Searchpath midi_search_path;
455 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
457 sp.blocks = 0; // not needed
458 session_dirs.push_back (sp);
460 SessionDirectory sdir(sp.path);
462 sound_search_path += sdir.sound_path ();
463 midi_search_path += sdir.midi_path ();
466 // reset the round-robin soundfile path thingie
467 last_rr_session_dir = session_dirs.begin();
471 Session::path_is_within_session (const std::string& path)
473 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
474 if (PBD::path_is_within (i->path, path)) {
482 Session::ensure_subdirs ()
486 dir = session_directory().peak_path();
488 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
489 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
493 dir = session_directory().sound_path();
495 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
496 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
500 dir = session_directory().midi_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = session_directory().dead_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().export_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = analysis_dir ();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = plugins_dir ();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 dir = externals_dir ();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
545 /** @param session_template directory containing session template, or empty.
546 * Caller must not hold process lock.
549 Session::create (const string& session_template, BusProfile* bus_profile)
551 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
556 if (ensure_subdirs ()) {
560 _writable = exists_and_writable (_path);
562 if (!session_template.empty()) {
563 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
565 FILE* in = g_fopen (in_path.c_str(), "rb");
568 /* no need to call legalize_for_path() since the string
569 * in session_template is already a legal path name
571 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
573 FILE* out = g_fopen (out_path.c_str(), "wb");
577 stringstream new_session;
580 size_t charsRead = fread (buf, sizeof(char), 1024, in);
583 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
588 if (charsRead == 0) {
591 new_session.write (buf, charsRead);
595 string file_contents = new_session.str();
596 size_t writeSize = file_contents.length();
597 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
598 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
606 if (!ARDOUR::Profile->get_trx()) {
607 /* Copy plugin state files from template to new session */
608 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
609 copy_recurse (template_plugins, plugins_dir ());
615 error << string_compose (_("Could not open %1 for writing session template"), out_path)
622 error << string_compose (_("Could not open session template %1 for reading"), in_path)
629 if (Profile->get_trx()) {
631 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
632 * Remember that this is a brand new session. Sessions
633 * loaded from saved state will get this range from the saved state.
636 set_session_range_location (0, 0);
638 /* Initial loop location, from absolute zero, length 10 seconds */
640 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
641 _locations->add (loc, true);
642 set_auto_loop_location (loc);
645 _state_of_the_state = Clean;
647 /* set up Master Out and Monitor Out if necessary */
652 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
654 // Waves Tracks: always create master bus for Tracks
655 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
656 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
664 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
665 r->input()->ensure_io (count, false, this);
666 r->output()->ensure_io (count, false, this);
672 /* prohibit auto-connect to master, because there isn't one */
673 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
677 add_routes (rl, false, false, false, PresentationInfo::max_order);
680 // Waves Tracks: Skip this. Always use autoconnection for Tracks
681 if (!ARDOUR::Profile->get_trx()) {
683 /* this allows the user to override settings with an environment variable.
686 if (no_auto_connect()) {
687 bus_profile->input_ac = AutoConnectOption (0);
688 bus_profile->output_ac = AutoConnectOption (0);
691 Config->set_input_auto_connect (bus_profile->input_ac);
692 Config->set_output_auto_connect (bus_profile->output_ac);
696 if (Config->get_use_monitor_bus() && bus_profile) {
697 add_monitor_section ();
704 Session::maybe_write_autosave()
706 if (dirty() && record_status() != Recording) {
707 save_state("", true);
712 Session::remove_pending_capture_state ()
714 std::string pending_state_file_path(_session_dir->root_path());
716 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
718 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
720 if (g_remove (pending_state_file_path.c_str()) != 0) {
721 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
722 pending_state_file_path, g_strerror (errno)) << endmsg;
726 /** Rename a state file.
727 * @param old_name Old snapshot name.
728 * @param new_name New snapshot name.
731 Session::rename_state (string old_name, string new_name)
733 if (old_name == _current_snapshot_name || old_name == _name) {
734 /* refuse to rename the current snapshot or the "main" one */
738 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
739 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
741 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
742 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
744 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
745 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
746 old_name, new_name, g_strerror(errno)) << endmsg;
750 /** Remove a state file.
751 * @param snapshot_name Snapshot name.
754 Session::remove_state (string snapshot_name)
756 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
757 // refuse to remove the current snapshot or the "main" one
761 std::string xml_path(_session_dir->root_path());
763 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
765 if (!create_backup_file (xml_path)) {
766 // don't remove it if a backup can't be made
767 // create_backup_file will log the error.
772 if (g_remove (xml_path.c_str()) != 0) {
773 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
774 xml_path, g_strerror (errno)) << endmsg;
778 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
780 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
782 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
785 std::string xml_path(_session_dir->root_path());
787 /* prevent concurrent saves from different threads */
789 Glib::Threads::Mutex::Lock lm (save_state_lock);
791 if (!_writable || (_state_of_the_state & CannotSave)) {
795 if (g_atomic_int_get(&_suspend_save)) {
799 _save_queued = false;
801 if (!_engine.connected ()) {
802 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), PROGRAM_NAME)
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;
983 if (root.get_property ("version", version)) {
984 if (version.find ('.') != string::npos) {
985 /* old school version format */
986 if (version[0] == '2') {
987 Stateful::loading_state_version = 2000;
989 Stateful::loading_state_version = 3000;
992 Stateful::loading_state_version = string_to<int32_t>(version);
995 /* no version implies very old version of Ardour */
996 Stateful::loading_state_version = 1000;
999 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1001 std::string backup_path(_session_dir->root_path());
1002 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1003 backup_path = Glib::build_filename (backup_path, backup_filename);
1005 // only create a backup for a given statefile version once
1007 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1009 VersionMismatch (xmlpath, backup_path);
1011 if (!copy_file (xmlpath, backup_path)) {;
1017 save_snapshot_name (snapshot_name);
1023 Session::load_options (const XMLNode& node)
1026 config.set_variables (node);
1031 Session::save_default_options ()
1033 return config.save_state();
1037 Session::get_state()
1043 Session::get_template()
1045 /* if we don't disable rec-enable, diskstreams
1046 will believe they need to store their capture
1047 sources in their state node.
1050 disable_record (false);
1052 return state(false);
1055 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1056 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1059 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1061 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1064 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1068 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1071 XMLNode* node = new XMLNode("TrackState"); // XXX
1074 PlaylistSet playlists; // SessionPlaylists
1077 // these will work with new_route_from_template()
1078 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1079 child = node->add_child ("Routes");
1080 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1081 if ((*i)->is_auditioner()) {
1084 if ((*i)->is_master() || (*i)->is_monitor()) {
1087 child->add_child_nocopy ((*i)->get_state());
1088 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1090 playlists.insert (track->playlist ());
1094 // on load, Regions in the playlists need to resolve and map Source-IDs
1095 // also playlist needs to be merged or created with new-name..
1096 // ... and Diskstream in tracks adjusted to use the correct playlist
1097 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1098 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1099 child->add_child_nocopy ((*i)->get_state ());
1100 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1101 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1102 const Region::SourceList& sl = (*s)->sources ();
1103 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1104 sources.insert (*sli);
1109 child = node->add_child ("Sources");
1110 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1111 child->add_child_nocopy ((*i)->get_state ());
1112 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1114 #ifdef PLATFORM_WINDOWS
1117 string p = fs->path ();
1118 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1122 std::string sn = Glib::build_filename (path, "share.axml");
1125 tree.set_root (node);
1126 return tree.write (sn.c_str());
1130 Session::state (bool full_state)
1133 XMLNode* node = new XMLNode("Session");
1136 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1138 child = node->add_child ("ProgramVersion");
1139 child->set_property("created-with", created_with);
1141 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1142 child->set_property("modified-with", modified_with);
1144 /* store configuration settings */
1148 node->set_property ("name", _name);
1149 node->set_property ("sample-rate", _base_frame_rate);
1151 if (session_dirs.size() > 1) {
1155 vector<space_and_path>::iterator i = session_dirs.begin();
1156 vector<space_and_path>::iterator next;
1158 ++i; /* skip the first one */
1162 while (i != session_dirs.end()) {
1166 if (next != session_dirs.end()) {
1167 p += G_SEARCHPATH_SEPARATOR;
1176 child = node->add_child ("Path");
1177 child->add_content (p);
1181 node->set_property ("end-is-free", _session_range_end_is_free);
1183 /* save the ID counter */
1185 node->set_property ("id-counter", ID::counter());
1187 node->set_property ("name-counter", name_id_counter ());
1189 /* save the event ID counter */
1191 node->set_property ("event-counter", Evoral::event_id_counter());
1193 /* save the VCA counter */
1195 node->set_property ("vca-counter", VCA::get_next_vca_number());
1197 /* various options */
1199 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1200 if (!midi_port_nodes.empty()) {
1201 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1202 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1203 midi_port_stuff->add_child_nocopy (**n);
1205 node->add_child_nocopy (*midi_port_stuff);
1208 XMLNode& cfgxml (config.get_variables ());
1210 /* exclude search-paths from template */
1211 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1212 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1213 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1215 node->add_child_nocopy (cfgxml);
1217 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1219 child = node->add_child ("Sources");
1222 Glib::Threads::Mutex::Lock sl (source_lock);
1224 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1226 /* Don't save information about non-file Sources, or
1227 * about non-destructive file sources that are empty
1228 * and unused by any regions.
1231 boost::shared_ptr<FileSource> fs;
1233 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1235 if (!fs->destructive()) {
1236 if (fs->empty() && !fs->used()) {
1241 child->add_child_nocopy (siter->second->get_state());
1246 child = node->add_child ("Regions");
1249 Glib::Threads::Mutex::Lock rl (region_lock);
1250 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1251 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1252 boost::shared_ptr<Region> r = i->second;
1253 /* only store regions not attached to playlists */
1254 if (r->playlist() == 0) {
1255 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1256 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1258 child->add_child_nocopy (r->get_state ());
1263 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1265 if (!cassocs.empty()) {
1266 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1268 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1269 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1270 can->set_property (X_("copy"), i->first->id());
1271 can->set_property (X_("original"), i->second->id());
1272 ca->add_child_nocopy (*can);
1280 node->add_child_nocopy (_locations->get_state());
1283 Locations loc (*this);
1284 const bool was_dirty = dirty();
1285 // for a template, just create a new Locations, populate it
1286 // with the default start and end, and get the state for that.
1287 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1288 range->set (max_framepos, 0);
1290 XMLNode& locations_state = loc.get_state();
1292 if (ARDOUR::Profile->get_trx() && _locations) {
1293 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1294 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1295 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1296 locations_state.add_child_nocopy ((*i)->get_state ());
1300 node->add_child_nocopy (locations_state);
1302 /* adding a location above will have marked the session
1303 * dirty. This is an artifact, so fix it if the session wasn't
1308 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1312 child = node->add_child ("Bundles");
1314 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1315 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1316 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1318 child->add_child_nocopy (b->get_state());
1323 node->add_child_nocopy (_vca_manager->get_state());
1325 child = node->add_child ("Routes");
1327 boost::shared_ptr<RouteList> r = routes.reader ();
1329 RoutePublicOrderSorter cmp;
1330 RouteList public_order (*r);
1331 public_order.sort (cmp);
1333 /* the sort should have put the monitor out first */
1336 assert (_monitor_out == public_order.front());
1339 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1340 if (!(*i)->is_auditioner()) {
1342 child->add_child_nocopy ((*i)->get_state());
1344 child->add_child_nocopy ((*i)->get_template());
1350 playlists->add_state (node, full_state);
1352 child = node->add_child ("RouteGroups");
1353 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1354 child->add_child_nocopy ((*i)->get_state());
1358 XMLNode* gain_child = node->add_child ("Click");
1359 gain_child->add_child_nocopy (_click_io->state (full_state));
1360 gain_child->add_child_nocopy (_click_gain->state (full_state));
1364 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1365 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1369 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1370 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1373 node->add_child_nocopy (_speakers->get_state());
1374 node->add_child_nocopy (_tempo_map->get_state());
1375 node->add_child_nocopy (get_control_protocol_state());
1378 node->add_child_copy (*_extra_xml);
1382 Glib::Threads::Mutex::Lock lm (lua_lock);
1385 luabridge::LuaRef savedstate ((*_lua_save)());
1386 saved = savedstate.cast<std::string>();
1388 lua.collect_garbage ();
1391 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1392 std::string b64s (b64);
1395 XMLNode* script_node = new XMLNode (X_("Script"));
1396 script_node->set_property (X_("lua"), LUA_VERSION);
1397 script_node->add_content (b64s);
1398 node->add_child_nocopy (*script_node);
1405 Session::get_control_protocol_state ()
1407 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1408 return cpm.get_state();
1412 Session::set_state (const XMLNode& node, int version)
1419 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1421 if (node.name() != X_("Session")) {
1422 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1426 node.get_property ("name", _name);
1428 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1430 _nominal_frame_rate = _base_frame_rate;
1432 assert (AudioEngine::instance()->running ());
1433 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1434 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1435 if (r.get_value_or (0)) {
1441 created_with = "unknown";
1442 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1443 child->get_property (X_("created-with"), created_with);
1446 setup_raid_path(_session_dir->root_path());
1448 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1451 if (node.get_property (X_("id-counter"), counter)) {
1452 ID::init_counter (counter);
1454 /* old sessions used a timebased counter, so fake
1455 * the startup ID counter based on a standard
1460 ID::init_counter (now);
1463 if (node.get_property (X_("name-counter"), counter)) {
1464 init_name_id_counter (counter);
1467 if (node.get_property (X_("event-counter"), counter)) {
1468 Evoral::init_event_id_counter (counter);
1471 if (node.get_property (X_("vca-counter"), counter)) {
1472 VCA::set_next_vca_number (counter);
1474 VCA::set_next_vca_number (1);
1477 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1478 _midi_ports->set_midi_port_states (child->children());
1481 IO::disable_connecting ();
1483 Stateful::save_extra_xml (node);
1485 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1486 load_options (*child);
1487 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1488 load_options (*child);
1490 error << _("Session: XML state has no options section") << endmsg;
1493 if (version >= 3000) {
1494 if ((child = find_named_node (node, "Metadata")) == 0) {
1495 warning << _("Session: XML state has no metadata section") << endmsg;
1496 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1501 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1502 _speakers->set_state (*child, version);
1505 if ((child = find_named_node (node, "Sources")) == 0) {
1506 error << _("Session: XML state has no sources section") << endmsg;
1508 } else if (load_sources (*child)) {
1512 if ((child = find_named_node (node, "TempoMap")) == 0) {
1513 error << _("Session: XML state has no Tempo Map section") << endmsg;
1515 } else if (_tempo_map->set_state (*child, version)) {
1519 if ((child = find_named_node (node, "Locations")) == 0) {
1520 error << _("Session: XML state has no locations section") << endmsg;
1522 } else if (_locations->set_state (*child, version)) {
1526 locations_changed ();
1528 if (_session_range_location) {
1529 AudioFileSource::set_header_position_offset (_session_range_location->start());
1532 if ((child = find_named_node (node, "Regions")) == 0) {
1533 error << _("Session: XML state has no Regions section") << endmsg;
1535 } else if (load_regions (*child)) {
1539 if ((child = find_named_node (node, "Playlists")) == 0) {
1540 error << _("Session: XML state has no playlists section") << endmsg;
1542 } else if (playlists->load (*this, *child)) {
1546 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1548 } else if (playlists->load_unused (*this, *child)) {
1552 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1553 if (load_compounds (*child)) {
1558 if (version >= 3000) {
1559 if ((child = find_named_node (node, "Bundles")) == 0) {
1560 warning << _("Session: XML state has no bundles section") << endmsg;
1563 /* We can't load Bundles yet as they need to be able
1564 * to convert from port names to Port objects, which can't happen until
1566 _bundle_xml_node = new XMLNode (*child);
1570 if (version < 3000) {
1571 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1572 error << _("Session: XML state has no diskstreams section") << endmsg;
1574 } else if (load_diskstreams_2X (*child, version)) {
1579 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1580 _vca_manager->set_state (*child, version);
1583 if ((child = find_named_node (node, "Routes")) == 0) {
1584 error << _("Session: XML state has no routes section") << endmsg;
1586 } else if (load_routes (*child, version)) {
1590 /* Now that we have Routes and masters loaded, connect them if appropriate */
1592 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1594 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1595 _diskstreams_2X.clear ();
1597 if (version >= 3000) {
1599 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1600 error << _("Session: XML state has no route groups section") << endmsg;
1602 } else if (load_route_groups (*child, version)) {
1606 } else if (version < 3000) {
1608 if ((child = find_named_node (node, "EditGroups")) == 0) {
1609 error << _("Session: XML state has no edit groups section") << endmsg;
1611 } else if (load_route_groups (*child, version)) {
1615 if ((child = find_named_node (node, "MixGroups")) == 0) {
1616 error << _("Session: XML state has no mix groups section") << endmsg;
1618 } else if (load_route_groups (*child, version)) {
1623 if ((child = find_named_node (node, "Click")) == 0) {
1624 warning << _("Session: XML state has no click section") << endmsg;
1625 } else if (_click_io) {
1626 setup_click_state (&node);
1629 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1630 ControlProtocolManager::instance().set_state (*child, version);
1633 if ((child = find_named_node (node, "Script"))) {
1634 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1635 if (!(*n)->is_content ()) { continue; }
1637 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1639 Glib::Threads::Mutex::Lock lm (lua_lock);
1640 (*_lua_load)(std::string ((const char*)buf, size));
1641 } catch (luabridge::LuaException const& e) {
1642 cerr << "LuaException:" << e.what () << endl;
1648 update_route_record_state ();
1650 /* here beginneth the second phase ... */
1651 set_snapshot_name (_current_snapshot_name);
1653 StateReady (); /* EMIT SIGNAL */
1666 Session::load_routes (const XMLNode& node, int version)
1669 XMLNodeConstIterator niter;
1670 RouteList new_routes;
1672 nlist = node.children();
1676 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1678 boost::shared_ptr<Route> route;
1679 if (version < 3000) {
1680 route = XMLRouteFactory_2X (**niter, version);
1682 route = XMLRouteFactory (**niter, version);
1686 error << _("Session: cannot create Route from XML description.") << endmsg;
1690 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1692 new_routes.push_back (route);
1695 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1697 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1699 BootMessage (_("Finished adding tracks/busses"));
1704 boost::shared_ptr<Route>
1705 Session::XMLRouteFactory (const XMLNode& node, int version)
1707 boost::shared_ptr<Route> ret;
1709 if (node.name() != "Route") {
1713 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1715 DataType type = DataType::AUDIO;
1716 node.get_property("default-type", type);
1718 assert (type != DataType::NIL);
1722 boost::shared_ptr<Track> track;
1724 if (type == DataType::AUDIO) {
1725 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1727 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1730 if (track->init()) {
1734 if (track->set_state (node, version)) {
1738 BOOST_MARK_TRACK (track);
1742 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1743 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1745 if (r->init () == 0 && r->set_state (node, version) == 0) {
1746 BOOST_MARK_ROUTE (r);
1754 boost::shared_ptr<Route>
1755 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1757 boost::shared_ptr<Route> ret;
1759 if (node.name() != "Route") {
1763 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1765 ds_prop = node.property (X_("diskstream"));
1768 DataType type = DataType::AUDIO;
1769 node.get_property("default-type", type);
1771 assert (type != DataType::NIL);
1775 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1776 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1780 if (i == _diskstreams_2X.end()) {
1781 error << _("Could not find diskstream for route") << endmsg;
1782 return boost::shared_ptr<Route> ();
1785 boost::shared_ptr<Track> track;
1787 if (type == DataType::AUDIO) {
1788 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1790 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1793 if (track->init()) {
1797 if (track->set_state (node, version)) {
1801 track->set_diskstream (*i);
1803 BOOST_MARK_TRACK (track);
1807 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1808 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1810 if (r->init () == 0 && r->set_state (node, version) == 0) {
1811 BOOST_MARK_ROUTE (r);
1820 Session::load_regions (const XMLNode& node)
1823 XMLNodeConstIterator niter;
1824 boost::shared_ptr<Region> region;
1826 nlist = node.children();
1830 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1831 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1832 error << _("Session: cannot create Region from XML description.");
1833 XMLProperty const * name = (**niter).property("name");
1836 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1847 Session::load_compounds (const XMLNode& node)
1849 XMLNodeList calist = node.children();
1850 XMLNodeConstIterator caiter;
1851 XMLProperty const * caprop;
1853 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1854 XMLNode* ca = *caiter;
1858 if ((caprop = ca->property (X_("original"))) == 0) {
1861 orig_id = caprop->value();
1863 if ((caprop = ca->property (X_("copy"))) == 0) {
1866 copy_id = caprop->value();
1868 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1869 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1871 if (!orig || !copy) {
1872 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1878 RegionFactory::add_compound_association (orig, copy);
1885 Session::load_nested_sources (const XMLNode& node)
1888 XMLNodeConstIterator niter;
1890 nlist = node.children();
1892 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1893 if ((*niter)->name() == "Source") {
1895 /* it may already exist, so don't recreate it unnecessarily
1898 XMLProperty const * prop = (*niter)->property (X_("id"));
1900 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1904 ID source_id (prop->value());
1906 if (!source_by_id (source_id)) {
1909 SourceFactory::create (*this, **niter, true);
1911 catch (failed_constructor& err) {
1912 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1919 boost::shared_ptr<Region>
1920 Session::XMLRegionFactory (const XMLNode& node, bool full)
1922 XMLProperty const * type = node.property("type");
1926 const XMLNodeList& nlist = node.children();
1928 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1929 XMLNode *child = (*niter);
1930 if (child->name() == "NestedSource") {
1931 load_nested_sources (*child);
1935 if (!type || type->value() == "audio") {
1936 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1937 } else if (type->value() == "midi") {
1938 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1941 } catch (failed_constructor& err) {
1942 return boost::shared_ptr<Region> ();
1945 return boost::shared_ptr<Region> ();
1948 boost::shared_ptr<AudioRegion>
1949 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1951 XMLProperty const * prop;
1952 boost::shared_ptr<Source> source;
1953 boost::shared_ptr<AudioSource> as;
1955 SourceList master_sources;
1956 uint32_t nchans = 1;
1959 if (node.name() != X_("Region")) {
1960 return boost::shared_ptr<AudioRegion>();
1963 node.get_property (X_("channels"), nchans);
1965 if ((prop = node.property ("name")) == 0) {
1966 cerr << "no name for this region\n";
1970 if ((prop = node.property (X_("source-0"))) == 0) {
1971 if ((prop = node.property ("source")) == 0) {
1972 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1973 return boost::shared_ptr<AudioRegion>();
1977 PBD::ID s_id (prop->value());
1979 if ((source = source_by_id (s_id)) == 0) {
1980 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1981 return boost::shared_ptr<AudioRegion>();
1984 as = boost::dynamic_pointer_cast<AudioSource>(source);
1986 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1987 return boost::shared_ptr<AudioRegion>();
1990 sources.push_back (as);
1992 /* pickup other channels */
1994 for (uint32_t n=1; n < nchans; ++n) {
1995 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1996 if ((prop = node.property (buf)) != 0) {
1998 PBD::ID id2 (prop->value());
2000 if ((source = source_by_id (id2)) == 0) {
2001 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2002 return boost::shared_ptr<AudioRegion>();
2005 as = boost::dynamic_pointer_cast<AudioSource>(source);
2007 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2008 return boost::shared_ptr<AudioRegion>();
2010 sources.push_back (as);
2014 for (uint32_t n = 0; n < nchans; ++n) {
2015 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2016 if ((prop = node.property (buf)) != 0) {
2018 PBD::ID id2 (prop->value());
2020 if ((source = source_by_id (id2)) == 0) {
2021 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2022 return boost::shared_ptr<AudioRegion>();
2025 as = boost::dynamic_pointer_cast<AudioSource>(source);
2027 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2028 return boost::shared_ptr<AudioRegion>();
2030 master_sources.push_back (as);
2035 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2037 /* a final detail: this is the one and only place that we know how long missing files are */
2039 if (region->whole_file()) {
2040 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2041 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2043 sfp->set_length (region->length());
2048 if (!master_sources.empty()) {
2049 if (master_sources.size() != nchans) {
2050 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2052 region->set_master_sources (master_sources);
2060 catch (failed_constructor& err) {
2061 return boost::shared_ptr<AudioRegion>();
2065 boost::shared_ptr<MidiRegion>
2066 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2068 XMLProperty const * prop;
2069 boost::shared_ptr<Source> source;
2070 boost::shared_ptr<MidiSource> ms;
2073 if (node.name() != X_("Region")) {
2074 return boost::shared_ptr<MidiRegion>();
2077 if ((prop = node.property ("name")) == 0) {
2078 cerr << "no name for this region\n";
2082 if ((prop = node.property (X_("source-0"))) == 0) {
2083 if ((prop = node.property ("source")) == 0) {
2084 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2085 return boost::shared_ptr<MidiRegion>();
2089 PBD::ID s_id (prop->value());
2091 if ((source = source_by_id (s_id)) == 0) {
2092 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2093 return boost::shared_ptr<MidiRegion>();
2096 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2098 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2099 return boost::shared_ptr<MidiRegion>();
2102 sources.push_back (ms);
2105 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2106 /* a final detail: this is the one and only place that we know how long missing files are */
2108 if (region->whole_file()) {
2109 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2110 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2112 sfp->set_length (region->length());
2120 catch (failed_constructor& err) {
2121 return boost::shared_ptr<MidiRegion>();
2126 Session::get_sources_as_xml ()
2129 XMLNode* node = new XMLNode (X_("Sources"));
2130 Glib::Threads::Mutex::Lock lm (source_lock);
2132 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2133 node->add_child_nocopy (i->second->get_state());
2140 Session::reset_write_sources (bool mark_write_complete, bool force)
2142 boost::shared_ptr<RouteList> rl = routes.reader();
2143 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2144 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2146 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2147 tr->reset_write_sources(mark_write_complete, force);
2148 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2154 Session::load_sources (const XMLNode& node)
2157 XMLNodeConstIterator niter;
2158 /* don't need this but it stops some
2159 * versions of gcc complaining about
2160 * discarded return values.
2162 boost::shared_ptr<Source> source;
2164 nlist = node.children();
2167 std::map<std::string, std::string> relocation;
2169 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2170 #ifdef PLATFORM_WINDOWS
2174 XMLNode srcnode (**niter);
2175 bool try_replace_abspath = true;
2179 #ifdef PLATFORM_WINDOWS
2180 // do not show "insert media" popups (files embedded from removable media).
2181 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2183 if ((source = XMLSourceFactory (srcnode)) == 0) {
2184 error << _("Session: cannot create Source from XML description.") << endmsg;
2186 #ifdef PLATFORM_WINDOWS
2187 SetErrorMode(old_mode);
2190 } catch (MissingSource& err) {
2191 #ifdef PLATFORM_WINDOWS
2192 SetErrorMode(old_mode);
2195 /* try previous abs path replacements first */
2196 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2197 std::string dir = Glib::path_get_dirname (err.path);
2198 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2199 if (rl != relocation.end ()) {
2200 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2201 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2202 srcnode.set_property ("origin", newpath);
2203 try_replace_abspath = false;
2210 _missing_file_replacement = "";
2212 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2213 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2214 PROGRAM_NAME) << endmsg;
2218 if (!no_questions_about_missing_files) {
2219 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2224 switch (user_choice) {
2226 /* user added a new search location
2227 * or selected a new absolute path,
2229 if (Glib::path_is_absolute (err.path)) {
2230 if (!_missing_file_replacement.empty ()) {
2231 /* replace origin, in XML */
2232 std::string newpath = Glib::build_filename (
2233 _missing_file_replacement, Glib::path_get_basename (err.path));
2234 srcnode.set_property ("origin", newpath);
2235 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2236 _missing_file_replacement = "";
2243 /* user asked to quit the entire session load */
2247 no_questions_about_missing_files = true;
2251 no_questions_about_missing_files = true;
2258 case DataType::AUDIO:
2259 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2262 case DataType::MIDI:
2263 /* The MIDI file is actually missing so
2264 * just create a new one in the same
2265 * location. Do not announce its
2269 if (!Glib::path_is_absolute (err.path)) {
2270 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2272 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2277 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2278 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2279 /* reset ID to match the missing one */
2280 source->set_id (**niter);
2281 /* Now we can announce it */
2282 SourceFactory::SourceCreated (source);
2293 boost::shared_ptr<Source>
2294 Session::XMLSourceFactory (const XMLNode& node)
2296 if (node.name() != "Source") {
2297 return boost::shared_ptr<Source>();
2301 /* note: do peak building in another thread when loading session state */
2302 return SourceFactory::create (*this, node, true);
2305 catch (failed_constructor& err) {
2306 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2307 return boost::shared_ptr<Source>();
2312 Session::save_template (string template_name, bool replace_existing)
2314 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2318 bool absolute_path = Glib::path_is_absolute (template_name);
2320 /* directory to put the template in */
2321 std::string template_dir_path;
2323 if (!absolute_path) {
2324 std::string user_template_dir(user_template_directory());
2326 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2327 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2328 user_template_dir, g_strerror (errno)) << endmsg;
2332 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2334 template_dir_path = template_name;
2337 if (!ARDOUR::Profile->get_trx()) {
2338 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2339 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2340 template_dir_path) << endmsg;
2344 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2345 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2346 template_dir_path, g_strerror (errno)) << endmsg;
2352 std::string template_file_path;
2354 if (ARDOUR::Profile->get_trx()) {
2355 template_file_path = template_name;
2357 if (absolute_path) {
2358 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2360 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2364 SessionSaveUnderway (); /* EMIT SIGNAL */
2369 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2370 tree.set_root (&get_template());
2373 if (!tree.write (template_file_path)) {
2374 error << _("template not saved") << endmsg;
2378 store_recent_templates (template_file_path);
2384 Session::refresh_disk_space ()
2386 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2388 Glib::Threads::Mutex::Lock lm (space_lock);
2390 /* get freespace on every FS that is part of the session path */
2392 _total_free_4k_blocks = 0;
2393 _total_free_4k_blocks_uncertain = false;
2395 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2396 #if defined(__NetBSD__)
2397 struct statvfs statfsbuf;
2399 statvfs (i->path.c_str(), &statfsbuf);
2401 struct statfs statfsbuf;
2403 statfs (i->path.c_str(), &statfsbuf);
2405 double const scale = statfsbuf.f_bsize / 4096.0;
2407 /* See if this filesystem is read-only */
2408 struct statvfs statvfsbuf;
2409 statvfs (i->path.c_str(), &statvfsbuf);
2411 /* f_bavail can be 0 if it is undefined for whatever
2412 filesystem we are looking at; Samba shares mounted
2413 via GVFS are an example of this.
2415 if (statfsbuf.f_bavail == 0) {
2416 /* block count unknown */
2418 i->blocks_unknown = true;
2419 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2420 /* read-only filesystem */
2422 i->blocks_unknown = false;
2424 /* read/write filesystem with known space */
2425 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2426 i->blocks_unknown = false;
2429 _total_free_4k_blocks += i->blocks;
2430 if (i->blocks_unknown) {
2431 _total_free_4k_blocks_uncertain = true;
2434 #elif defined PLATFORM_WINDOWS
2435 vector<string> scanned_volumes;
2436 vector<string>::iterator j;
2437 vector<space_and_path>::iterator i;
2438 DWORD nSectorsPerCluster, nBytesPerSector,
2439 nFreeClusters, nTotalClusters;
2443 _total_free_4k_blocks = 0;
2445 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2446 strncpy (disk_drive, (*i).path.c_str(), 3);
2450 volume_found = false;
2451 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2453 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2454 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2455 i->blocks = (uint32_t)(nFreeBytes / 4096);
2457 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2458 if (0 == j->compare(disk_drive)) {
2459 volume_found = true;
2464 if (!volume_found) {
2465 scanned_volumes.push_back(disk_drive);
2466 _total_free_4k_blocks += i->blocks;
2471 if (0 == _total_free_4k_blocks) {
2472 strncpy (disk_drive, path().c_str(), 3);
2475 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2477 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2478 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2479 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2486 Session::get_best_session_directory_for_new_audio ()
2488 vector<space_and_path>::iterator i;
2489 string result = _session_dir->root_path();
2491 /* handle common case without system calls */
2493 if (session_dirs.size() == 1) {
2497 /* OK, here's the algorithm we're following here:
2499 We want to select which directory to use for
2500 the next file source to be created. Ideally,
2501 we'd like to use a round-robin process so as to
2502 get maximum performance benefits from splitting
2503 the files across multiple disks.
2505 However, in situations without much diskspace, an
2506 RR approach may end up filling up a filesystem
2507 with new files while others still have space.
2508 Its therefore important to pay some attention to
2509 the freespace in the filesystem holding each
2510 directory as well. However, if we did that by
2511 itself, we'd keep creating new files in the file
2512 system with the most space until it was as full
2513 as all others, thus negating any performance
2514 benefits of this RAID-1 like approach.
2516 So, we use a user-configurable space threshold. If
2517 there are at least 2 filesystems with more than this
2518 much space available, we use RR selection between them.
2519 If not, then we pick the filesystem with the most space.
2521 This gets a good balance between the two
2525 refresh_disk_space ();
2527 int free_enough = 0;
2529 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2530 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2535 if (free_enough >= 2) {
2536 /* use RR selection process, ensuring that the one
2540 i = last_rr_session_dir;
2543 if (++i == session_dirs.end()) {
2544 i = session_dirs.begin();
2547 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2548 SessionDirectory sdir(i->path);
2549 if (sdir.create ()) {
2551 last_rr_session_dir = i;
2556 } while (i != last_rr_session_dir);
2560 /* pick FS with the most freespace (and that
2561 seems to actually work ...)
2564 vector<space_and_path> sorted;
2565 space_and_path_ascending_cmp cmp;
2567 sorted = session_dirs;
2568 sort (sorted.begin(), sorted.end(), cmp);
2570 for (i = sorted.begin(); i != sorted.end(); ++i) {
2571 SessionDirectory sdir(i->path);
2572 if (sdir.create ()) {
2574 last_rr_session_dir = i;
2584 Session::automation_dir () const
2586 return Glib::build_filename (_path, automation_dir_name);
2590 Session::analysis_dir () const
2592 return Glib::build_filename (_path, analysis_dir_name);
2596 Session::plugins_dir () const
2598 return Glib::build_filename (_path, plugins_dir_name);
2602 Session::externals_dir () const
2604 return Glib::build_filename (_path, externals_dir_name);
2608 Session::load_bundles (XMLNode const & node)
2610 XMLNodeList nlist = node.children();
2611 XMLNodeConstIterator niter;
2615 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2616 if ((*niter)->name() == "InputBundle") {
2617 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2618 } else if ((*niter)->name() == "OutputBundle") {
2619 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2621 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2630 Session::load_route_groups (const XMLNode& node, int version)
2632 XMLNodeList nlist = node.children();
2633 XMLNodeConstIterator niter;
2637 if (version >= 3000) {
2639 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2640 if ((*niter)->name() == "RouteGroup") {
2641 RouteGroup* rg = new RouteGroup (*this, "");
2642 add_route_group (rg);
2643 rg->set_state (**niter, version);
2647 } else if (version < 3000) {
2649 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2650 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2651 RouteGroup* rg = new RouteGroup (*this, "");
2652 add_route_group (rg);
2653 rg->set_state (**niter, version);
2662 state_file_filter (const string &str, void* /*arg*/)
2664 return (str.length() > strlen(statefile_suffix) &&
2665 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2669 remove_end(string state)
2671 string statename(state);
2673 string::size_type start,end;
2674 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2675 statename = statename.substr (start+1);
2678 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2679 end = statename.length();
2682 return string(statename.substr (0, end));
2686 Session::possible_states (string path)
2688 vector<string> states;
2689 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2691 transform(states.begin(), states.end(), states.begin(), remove_end);
2693 sort (states.begin(), states.end());
2699 Session::possible_states () const
2701 return possible_states(_path);
2705 Session::new_route_group (const std::string& name)
2707 RouteGroup* rg = NULL;
2709 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2710 if ((*i)->name () == name) {
2717 rg = new RouteGroup (*this, name);
2718 add_route_group (rg);
2724 Session::add_route_group (RouteGroup* g)
2726 _route_groups.push_back (g);
2727 route_group_added (g); /* EMIT SIGNAL */
2729 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2730 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2731 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2737 Session::remove_route_group (RouteGroup& rg)
2739 list<RouteGroup*>::iterator i;
2741 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2742 _route_groups.erase (i);
2745 route_group_removed (); /* EMIT SIGNAL */
2749 /** Set a new order for our route groups, without adding or removing any.
2750 * @param groups Route group list in the new order.
2753 Session::reorder_route_groups (list<RouteGroup*> groups)
2755 _route_groups = groups;
2757 route_groups_reordered (); /* EMIT SIGNAL */
2763 Session::route_group_by_name (string name)
2765 list<RouteGroup *>::iterator i;
2767 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2768 if ((*i)->name() == name) {
2776 Session::all_route_group() const
2778 return *_all_route_group;
2782 Session::add_commands (vector<Command*> const & cmds)
2784 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2790 Session::add_command (Command* const cmd)
2792 assert (_current_trans);
2793 DEBUG_UNDO_HISTORY (
2794 string_compose ("Current Undo Transaction %1, adding command: %2",
2795 _current_trans->name (),
2797 _current_trans->add_command (cmd);
2800 PBD::StatefulDiffCommand*
2801 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2803 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2809 Session::begin_reversible_command (const string& name)
2811 begin_reversible_command (g_quark_from_string (name.c_str ()));
2814 /** Begin a reversible command using a GQuark to identify it.
2815 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2816 * but there must be as many begin...()s as there are commit...()s.
2819 Session::begin_reversible_command (GQuark q)
2821 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2822 to hold all the commands that are committed. This keeps the order of
2823 commands correct in the history.
2826 if (_current_trans == 0) {
2827 DEBUG_UNDO_HISTORY (string_compose (
2828 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2830 /* start a new transaction */
2831 assert (_current_trans_quarks.empty ());
2832 _current_trans = new UndoTransaction();
2833 _current_trans->set_name (g_quark_to_string (q));
2835 DEBUG_UNDO_HISTORY (
2836 string_compose ("Begin Reversible Command, current transaction: %1",
2837 _current_trans->name ()));
2840 _current_trans_quarks.push_front (q);
2844 Session::abort_reversible_command ()
2846 if (_current_trans != 0) {
2847 DEBUG_UNDO_HISTORY (
2848 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2849 _current_trans->clear();
2850 delete _current_trans;
2852 _current_trans_quarks.clear();
2857 Session::commit_reversible_command (Command *cmd)
2859 assert (_current_trans);
2860 assert (!_current_trans_quarks.empty ());
2865 DEBUG_UNDO_HISTORY (
2866 string_compose ("Current Undo Transaction %1, adding command: %2",
2867 _current_trans->name (),
2869 _current_trans->add_command (cmd);
2872 DEBUG_UNDO_HISTORY (
2873 string_compose ("Commit Reversible Command, current transaction: %1",
2874 _current_trans->name ()));
2876 _current_trans_quarks.pop_front ();
2878 if (!_current_trans_quarks.empty ()) {
2879 DEBUG_UNDO_HISTORY (
2880 string_compose ("Commit Reversible Command, transaction is not "
2881 "top-level, current transaction: %1",
2882 _current_trans->name ()));
2883 /* the transaction we're committing is not the top-level one */
2887 if (_current_trans->empty()) {
2888 /* no commands were added to the transaction, so just get rid of it */
2889 DEBUG_UNDO_HISTORY (
2890 string_compose ("Commit Reversible Command, No commands were "
2891 "added to current transaction: %1",
2892 _current_trans->name ()));
2893 delete _current_trans;
2898 gettimeofday (&now, 0);
2899 _current_trans->set_timestamp (now);
2901 _history.add (_current_trans);
2906 accept_all_audio_files (const string& path, void* /*arg*/)
2908 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2912 if (!AudioFileSource::safe_audio_file_extension (path)) {
2920 accept_all_midi_files (const string& path, void* /*arg*/)
2922 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2926 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2927 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2928 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2932 accept_all_state_files (const string& path, void* /*arg*/)
2934 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2938 std::string const statefile_ext (statefile_suffix);
2939 if (path.length() >= statefile_ext.length()) {
2940 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2947 Session::find_all_sources (string path, set<string>& result)
2952 if (!tree.read (path)) {
2956 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2961 XMLNodeConstIterator niter;
2963 nlist = node->children();
2967 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2969 XMLProperty const * prop;
2971 if ((prop = (*niter)->property (X_("type"))) == 0) {
2975 DataType type (prop->value());
2977 if ((prop = (*niter)->property (X_("name"))) == 0) {
2981 if (Glib::path_is_absolute (prop->value())) {
2982 /* external file, ignore */
2990 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2991 result.insert (found_path);
2999 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3001 vector<string> state_files;
3003 string this_snapshot_path;
3009 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3010 ripped = ripped.substr (0, ripped.length() - 1);
3013 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3015 if (state_files.empty()) {
3020 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3021 this_snapshot_path += statefile_suffix;
3023 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3025 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3027 if (exclude_this_snapshot && *i == this_snapshot_path) {
3028 cerr << "\texcluded\n";
3033 if (find_all_sources (*i, result) < 0) {
3041 struct RegionCounter {
3042 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3043 AudioSourceList::iterator iter;
3044 boost::shared_ptr<Region> region;
3047 RegionCounter() : count (0) {}
3051 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3053 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3054 return r.get_value_or (1);
3058 Session::cleanup_regions ()
3060 bool removed = false;
3061 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3063 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3065 uint32_t used = playlists->region_use_count (i->second);
3067 if (used == 0 && !i->second->automatic ()) {
3068 boost::weak_ptr<Region> w = i->second;
3071 RegionFactory::map_remove (w);
3078 // re-check to remove parent references of compound regions
3079 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3080 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3084 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3085 if (0 == playlists->region_use_count (i->second)) {
3086 boost::weak_ptr<Region> w = i->second;
3088 RegionFactory::map_remove (w);
3095 /* dump the history list */
3102 Session::can_cleanup_peakfiles () const
3104 if (deletion_in_progress()) {
3107 if (!_writable || (_state_of_the_state & CannotSave)) {
3108 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3111 if (record_status() == Recording) {
3112 error << _("Cannot cleanup peak-files while recording") << endmsg;
3119 Session::cleanup_peakfiles ()
3121 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3126 assert (can_cleanup_peakfiles ());
3127 assert (!peaks_cleanup_in_progres());
3129 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3131 int timeout = 5000; // 5 seconds
3132 while (!SourceFactory::files_with_peaks.empty()) {
3133 Glib::usleep (1000);
3134 if (--timeout < 0) {
3135 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3136 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3141 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3142 boost::shared_ptr<AudioSource> as;
3143 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3144 as->close_peakfile();
3148 PBD::clear_directory (session_directory().peak_path());
3150 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3152 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3153 boost::shared_ptr<AudioSource> as;
3154 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3155 SourceFactory::setup_peakfile(as, true);
3162 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3164 pl->deep_sources (*all_sources);
3168 Session::cleanup_sources (CleanupReport& rep)
3170 // FIXME: needs adaptation to midi
3172 vector<boost::shared_ptr<Source> > dead_sources;
3175 vector<string> candidates;
3176 vector<string> unused;
3177 set<string> sources_used_by_all_snapshots;
3184 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3186 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3188 /* this is mostly for windows which doesn't allow file
3189 * renaming if the file is in use. But we don't special
3190 * case it because we need to know if this causes
3191 * problems, and the easiest way to notice that is to
3192 * keep it in place for all platforms.
3195 request_stop (false);
3197 _butler->wait_until_finished ();
3199 /* consider deleting all unused playlists */
3201 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3206 /* sync the "all regions" property of each playlist with its current state */
3208 playlists->sync_all_regions_with_regions ();
3210 /* find all un-used sources */
3215 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3217 SourceMap::iterator tmp;
3222 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3226 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3227 dead_sources.push_back (i->second);
3228 i->second->drop_references ();
3234 /* build a list of all the possible audio directories for the session */
3236 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3237 SessionDirectory sdir ((*i).path);
3238 asp += sdir.sound_path();
3240 audio_path += asp.to_string();
3243 /* build a list of all the possible midi directories for the session */
3245 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3246 SessionDirectory sdir ((*i).path);
3247 msp += sdir.midi_path();
3249 midi_path += msp.to_string();
3251 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3252 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3254 /* add sources from all other snapshots as "used", but don't use this
3255 snapshot because the state file on disk still references sources we
3256 may have already dropped.
3259 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3261 /* Although the region factory has a list of all regions ever created
3262 * for this session, we're only interested in regions actually in
3263 * playlists right now. So merge all playlist regions lists together.
3265 * This will include the playlists used within compound regions.
3268 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3270 /* add our current source list
3273 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3274 boost::shared_ptr<FileSource> fs;
3275 SourceMap::iterator tmp = i;
3278 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3284 /* this is mostly for windows which doesn't allow file
3285 * renaming if the file is in use. But we do not special
3286 * case it because we need to know if this causes
3287 * problems, and the easiest way to notice that is to
3288 * keep it in place for all platforms.
3293 if (!fs->is_stub()) {
3295 /* Note that we're checking a list of all
3296 * sources across all snapshots with the list
3297 * of sources used by this snapshot.
3300 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3301 /* this source is in use by this snapshot */
3302 sources_used_by_all_snapshots.insert (fs->path());
3303 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3305 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3306 /* this source is NOT in use by this snapshot */
3308 /* remove all related regions from RegionFactory master list */
3310 RegionFactory::remove_regions_using_source (i->second);
3312 /* remove from our current source list
3313 * also. We may not remove it from
3314 * disk, because it may be used by
3315 * other snapshots, but it isn't used inside this
3316 * snapshot anymore, so we don't need a
3327 /* now check each candidate source to see if it exists in the list of
3328 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3331 cerr << "Candidates: " << candidates.size() << endl;
3332 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3334 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3339 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3341 tmppath1 = canonical_path (spath);
3342 tmppath2 = canonical_path ((*i));
3344 cerr << "\t => " << tmppath2 << endl;
3346 if (tmppath1 == tmppath2) {
3353 unused.push_back (spath);
3357 cerr << "Actually unused: " << unused.size() << endl;
3359 if (unused.empty()) {
3365 /* now try to move all unused files into the "dead" directory(ies) */
3367 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3372 /* don't move the file across filesystems, just
3373 * stick it in the `dead_dir_name' directory
3374 * on whichever filesystem it was already on.
3377 if ((*x).find ("/sounds/") != string::npos) {
3379 /* old school, go up 1 level */
3381 newpath = Glib::path_get_dirname (*x); // "sounds"
3382 newpath = Glib::path_get_dirname (newpath); // "session-name"
3386 /* new school, go up 4 levels */
3388 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3389 newpath = Glib::path_get_dirname (newpath); // "session-name"
3390 newpath = Glib::path_get_dirname (newpath); // "interchange"
3391 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3394 newpath = Glib::build_filename (newpath, dead_dir_name);
3396 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3397 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3401 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3403 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3405 /* the new path already exists, try versioning */
3407 char buf[PATH_MAX+1];
3411 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3414 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3415 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3419 if (version == 999) {
3420 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3424 newpath = newpath_v;
3429 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3430 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3431 newpath, g_strerror (errno)) << endmsg;
3435 /* see if there an easy to find peakfile for this file, and remove it. */
3437 string base = Glib::path_get_basename (*x);
3438 base += "%A"; /* this is what we add for the channel suffix of all native files,
3439 * or for the first channel of embedded files. it will miss
3440 * some peakfiles for other channels
3442 string peakpath = construct_peak_filepath (base);
3444 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3445 if (::g_unlink (peakpath.c_str ()) != 0) {
3446 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3447 g_strerror (errno)) << endmsg;
3448 /* try to back out */
3449 ::g_rename (newpath.c_str (), _path.c_str ());
3454 rep.paths.push_back (*x);
3455 rep.space += statbuf.st_size;
3458 /* dump the history list */
3462 /* save state so we don't end up a session file
3463 * referring to non-existent sources.
3470 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3476 Session::cleanup_trash_sources (CleanupReport& rep)
3478 // FIXME: needs adaptation for MIDI
3480 vector<space_and_path>::iterator i;
3486 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3488 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3490 clear_directory (dead_dir, &rep.space, &rep.paths);
3497 Session::set_dirty ()
3499 /* return early if there's nothing to do */
3504 /* never mark session dirty during loading */
3505 if (_state_of_the_state & Loading) {
3509 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3510 DirtyChanged(); /* EMIT SIGNAL */
3514 Session::set_clean ()
3516 bool was_dirty = dirty();
3518 _state_of_the_state = Clean;
3521 DirtyChanged(); /* EMIT SIGNAL */
3526 Session::set_deletion_in_progress ()
3528 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3532 Session::clear_deletion_in_progress ()
3534 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3538 Session::add_controllable (boost::shared_ptr<Controllable> c)
3540 /* this adds a controllable to the list managed by the Session.
3541 this is a subset of those managed by the Controllable class
3542 itself, and represents the only ones whose state will be saved
3543 as part of the session.
3546 Glib::Threads::Mutex::Lock lm (controllables_lock);
3547 controllables.insert (c);
3550 struct null_deleter { void operator()(void const *) const {} };
3553 Session::remove_controllable (Controllable* c)
3555 if (_state_of_the_state & Deletion) {
3559 Glib::Threads::Mutex::Lock lm (controllables_lock);
3561 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3563 if (x != controllables.end()) {
3564 controllables.erase (x);
3568 boost::shared_ptr<Controllable>
3569 Session::controllable_by_id (const PBD::ID& id)
3571 Glib::Threads::Mutex::Lock lm (controllables_lock);
3573 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3574 if ((*i)->id() == id) {
3579 return boost::shared_ptr<Controllable>();
3582 boost::shared_ptr<Controllable>
3583 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3585 boost::shared_ptr<Controllable> c;
3586 boost::shared_ptr<Stripable> s;
3587 boost::shared_ptr<Route> r;
3589 switch (desc.top_level_type()) {
3590 case ControllableDescriptor::NamedRoute:
3592 std::string str = desc.top_level_name();
3594 if (str == "Master" || str == "master") {
3596 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3598 } else if (str == "auditioner") {
3601 s = route_by_name (desc.top_level_name());
3607 case ControllableDescriptor::PresentationOrderRoute:
3608 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3611 case ControllableDescriptor::PresentationOrderTrack:
3612 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3615 case ControllableDescriptor::PresentationOrderBus:
3616 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3619 case ControllableDescriptor::PresentationOrderVCA:
3620 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3623 case ControllableDescriptor::SelectionCount:
3624 s = route_by_selected_count (desc.selection_id());
3632 r = boost::dynamic_pointer_cast<Route> (s);
3634 switch (desc.subtype()) {
3635 case ControllableDescriptor::Gain:
3636 c = s->gain_control ();
3639 case ControllableDescriptor::Trim:
3640 c = s->trim_control ();
3643 case ControllableDescriptor::Solo:
3644 c = s->solo_control();
3647 case ControllableDescriptor::Mute:
3648 c = s->mute_control();
3651 case ControllableDescriptor::Recenable:
3652 c = s->rec_enable_control ();
3655 case ControllableDescriptor::PanDirection:
3656 c = s->pan_azimuth_control();
3659 case ControllableDescriptor::PanWidth:
3660 c = s->pan_width_control();
3663 case ControllableDescriptor::PanElevation:
3664 c = s->pan_elevation_control();
3667 case ControllableDescriptor::Balance:
3668 /* XXX simple pan control */
3671 case ControllableDescriptor::PluginParameter:
3673 uint32_t plugin = desc.target (0);
3674 uint32_t parameter_index = desc.target (1);
3676 /* revert to zero based counting */
3682 if (parameter_index > 0) {
3690 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3693 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3694 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3699 case ControllableDescriptor::SendGain: {
3700 uint32_t send = desc.target (0);
3707 c = r->send_level_controllable (send);
3712 /* relax and return a null pointer */
3720 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3723 Stateful::add_instant_xml (node, _path);
3726 if (write_to_config) {
3727 Config->add_instant_xml (node);
3732 Session::instant_xml (const string& node_name)
3734 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3735 if (get_disable_all_loaded_plugins ()) {
3739 return Stateful::instant_xml (node_name, _path);
3743 Session::save_history (string snapshot_name)
3751 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3752 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3756 if (snapshot_name.empty()) {
3757 snapshot_name = _current_snapshot_name;
3760 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3761 const string backup_filename = history_filename + backup_suffix;
3762 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3763 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3765 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3766 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3767 error << _("could not backup old history file, current history not saved") << endmsg;
3772 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3774 if (!tree.write (xml_path))
3776 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3778 if (g_remove (xml_path.c_str()) != 0) {
3779 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3780 xml_path, g_strerror (errno)) << endmsg;
3782 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3783 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3784 backup_path, g_strerror (errno)) << endmsg;
3794 Session::restore_history (string snapshot_name)
3798 if (snapshot_name.empty()) {
3799 snapshot_name = _current_snapshot_name;
3802 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3803 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3805 info << "Loading history from " << xml_path << endmsg;
3807 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3808 info << string_compose (_("%1: no history file \"%2\" for this session."),
3809 _name, xml_path) << endmsg;
3813 if (!tree.read (xml_path)) {
3814 error << string_compose (_("Could not understand session history file \"%1\""),
3815 xml_path) << endmsg;
3822 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3825 UndoTransaction* ut = new UndoTransaction ();
3828 ut->set_name(t->property("name")->value());
3829 stringstream ss(t->property("tv-sec")->value());
3831 ss.str(t->property("tv-usec")->value());
3833 ut->set_timestamp(tv);
3835 for (XMLNodeConstIterator child_it = t->children().begin();
3836 child_it != t->children().end(); child_it++)
3838 XMLNode *n = *child_it;
3841 if (n->name() == "MementoCommand" ||
3842 n->name() == "MementoUndoCommand" ||
3843 n->name() == "MementoRedoCommand") {
3845 if ((c = memento_command_factory(n))) {
3849 } else if (n->name() == "NoteDiffCommand") {
3850 PBD::ID id (n->property("midi-source")->value());
3851 boost::shared_ptr<MidiSource> midi_source =
3852 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3854 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3856 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3859 } else if (n->name() == "SysExDiffCommand") {
3861 PBD::ID id (n->property("midi-source")->value());
3862 boost::shared_ptr<MidiSource> midi_source =
3863 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3865 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3867 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3870 } else if (n->name() == "PatchChangeDiffCommand") {
3872 PBD::ID id (n->property("midi-source")->value());
3873 boost::shared_ptr<MidiSource> midi_source =
3874 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3876 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3878 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3881 } else if (n->name() == "StatefulDiffCommand") {
3882 if ((c = stateful_diff_command_factory (n))) {
3883 ut->add_command (c);
3886 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3897 Session::config_changed (std::string p, bool ours)
3903 if (p == "seamless-loop") {
3905 } else if (p == "rf-speed") {
3907 } else if (p == "auto-loop") {
3909 } else if (p == "session-monitoring") {
3911 } else if (p == "auto-input") {
3913 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3914 /* auto-input only makes a difference if we're rolling */
3915 set_track_monitor_input_status (!config.get_auto_input());
3918 } else if (p == "punch-in") {
3922 if ((location = _locations->auto_punch_location()) != 0) {
3924 if (config.get_punch_in ()) {
3925 replace_event (SessionEvent::PunchIn, location->start());
3927 remove_event (location->start(), SessionEvent::PunchIn);
3931 } else if (p == "punch-out") {
3935 if ((location = _locations->auto_punch_location()) != 0) {
3937 if (config.get_punch_out()) {
3938 replace_event (SessionEvent::PunchOut, location->end());
3940 clear_events (SessionEvent::PunchOut);
3944 } else if (p == "edit-mode") {
3946 Glib::Threads::Mutex::Lock lm (playlists->lock);
3948 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3949 (*i)->set_edit_mode (Config->get_edit_mode ());
3952 } else if (p == "use-video-sync") {
3954 waiting_for_sync_offset = config.get_use_video_sync();
3956 } else if (p == "mmc-control") {
3958 //poke_midi_thread ();
3960 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3962 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3964 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3966 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3968 } else if (p == "midi-control") {
3970 //poke_midi_thread ();
3972 } else if (p == "raid-path") {
3974 setup_raid_path (config.get_raid_path());
3976 } else if (p == "timecode-format") {
3980 } else if (p == "video-pullup") {
3984 } else if (p == "seamless-loop") {
3986 if (play_loop && transport_rolling()) {
3987 // to reset diskstreams etc
3988 request_play_loop (true);
3991 } else if (p == "rf-speed") {
3993 cumulative_rf_motion = 0;
3996 } else if (p == "click-sound") {
3998 setup_click_sounds (1);
4000 } else if (p == "click-emphasis-sound") {
4002 setup_click_sounds (-1);
4004 } else if (p == "clicking") {
4006 if (Config->get_clicking()) {
4007 if (_click_io && click_data) { // don't require emphasis data
4014 } else if (p == "click-record-only") {
4016 _click_rec_only = Config->get_click_record_only();
4018 } else if (p == "click-gain") {
4021 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4024 } else if (p == "send-mtc") {
4026 if (Config->get_send_mtc ()) {
4027 /* mark us ready to send */
4028 next_quarter_frame_to_send = 0;
4031 } else if (p == "send-mmc") {
4033 _mmc->enable_send (Config->get_send_mmc ());
4035 } else if (p == "jack-time-master") {
4037 engine().reset_timebase ();
4039 } else if (p == "native-file-header-format") {
4041 if (!first_file_header_format_reset) {
4042 reset_native_file_format ();
4045 first_file_header_format_reset = false;
4047 } else if (p == "native-file-data-format") {
4049 if (!first_file_data_format_reset) {
4050 reset_native_file_format ();
4053 first_file_data_format_reset = false;
4055 } else if (p == "external-sync") {
4056 if (!config.get_external_sync()) {
4057 drop_sync_source ();
4059 switch_to_sync_source (Config->get_sync_source());
4061 } else if (p == "denormal-model") {
4063 } else if (p == "history-depth") {
4064 set_history_depth (Config->get_history_depth());
4065 } else if (p == "remote-model") {
4066 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4069 } else if (p == "initial-program-change") {
4071 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4074 buf[0] = MIDI::program; // channel zero by default
4075 buf[1] = (Config->get_initial_program_change() & 0x7f);
4077 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4079 } else if (p == "solo-mute-override") {
4080 // catch_up_on_solo_mute_override ();
4081 } else if (p == "listen-position" || p == "pfl-position") {
4082 listen_position_changed ();
4083 } else if (p == "solo-control-is-listen-control") {
4084 solo_control_mode_changed ();
4085 } else if (p == "solo-mute-gain") {
4086 _solo_cut_control->Changed (true, Controllable::NoGroup);
4087 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4088 last_timecode_valid = false;
4089 } else if (p == "playback-buffer-seconds") {
4090 AudioSource::allocate_working_buffers (frame_rate());
4091 } else if (p == "ltc-source-port") {
4092 reconnect_ltc_input ();
4093 } else if (p == "ltc-sink-port") {
4094 reconnect_ltc_output ();
4095 } else if (p == "timecode-generator-offset") {
4096 ltc_tx_parse_offset();
4097 } else if (p == "auto-return-target-list") {
4098 follow_playhead_priority ();
4105 Session::set_history_depth (uint32_t d)
4107 _history.set_depth (d);
4111 Session::load_diskstreams_2X (XMLNode const & node, int)
4114 XMLNodeConstIterator citer;
4116 clist = node.children();
4118 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4121 /* diskstreams added automatically by DiskstreamCreated handler */
4122 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4123 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4124 _diskstreams_2X.push_back (dsp);
4126 error << _("Session: unknown diskstream type in XML") << endmsg;
4130 catch (failed_constructor& err) {
4131 error << _("Session: could not load diskstream via XML state") << endmsg;
4139 /** Connect things to the MMC object */
4141 Session::setup_midi_machine_control ()
4143 _mmc = new MIDI::MachineControl;
4145 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4146 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4148 if (!async_out || !async_out) {
4152 /* XXXX argh, passing raw pointers back into libmidi++ */
4154 MIDI::Port* mmc_in = async_in.get();
4155 MIDI::Port* mmc_out = async_out.get();
4157 _mmc->set_ports (mmc_in, mmc_out);
4159 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4160 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4161 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4162 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4163 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4164 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4165 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4166 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4167 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4168 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4169 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4170 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4171 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4173 /* also handle MIDI SPP because its so common */
4175 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4176 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4177 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4180 boost::shared_ptr<Controllable>
4181 Session::solo_cut_control() const
4183 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4184 * controls in Ardour that currently get presented to the user in the GUI that require
4185 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4187 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4188 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4191 return _solo_cut_control;
4195 Session::save_snapshot_name (const std::string & n)
4197 /* assure Stateful::_instant_xml is loaded
4198 * add_instant_xml() only adds to existing data and defaults
4199 * to use an empty Tree otherwise
4201 instant_xml ("LastUsedSnapshot");
4203 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4204 last_used_snapshot->set_property ("name", n);
4205 add_instant_xml (*last_used_snapshot, false);
4209 Session::set_snapshot_name (const std::string & n)
4211 _current_snapshot_name = n;
4212 save_snapshot_name (n);
4216 Session::rename (const std::string& new_name)
4218 string legal_name = legalize_for_path (new_name);
4224 string const old_sources_root = _session_dir->sources_root();
4226 if (!_writable || (_state_of_the_state & CannotSave)) {
4227 error << _("Cannot rename read-only session.") << endmsg;
4228 return 0; // don't show "messed up" warning
4230 if (record_status() == Recording) {
4231 error << _("Cannot rename session while recording") << endmsg;
4232 return 0; // don't show "messed up" warning
4235 StateProtector stp (this);
4240 * interchange subdirectory
4244 * Backup files are left unchanged and not renamed.
4247 /* Windows requires that we close all files before attempting the
4248 * rename. This works on other platforms, but isn't necessary there.
4249 * Leave it in place for all platforms though, since it may help
4250 * catch issues that could arise if the way Source files work ever
4251 * change (since most developers are not using Windows).
4254 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4255 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4261 /* pass one: not 100% safe check that the new directory names don't
4265 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4269 /* this is a stupid hack because Glib::path_get_dirname() is
4270 * lexical-only, and so passing it /a/b/c/ gives a different
4271 * result than passing it /a/b/c ...
4274 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4275 oldstr = oldstr.substr (0, oldstr.length() - 1);
4278 string base = Glib::path_get_dirname (oldstr);
4280 newstr = Glib::build_filename (base, legal_name);
4282 cerr << "Looking for " << newstr << endl;
4284 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4285 cerr << " exists\n";
4294 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4300 /* this is a stupid hack because Glib::path_get_dirname() is
4301 * lexical-only, and so passing it /a/b/c/ gives a different
4302 * result than passing it /a/b/c ...
4305 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4306 oldstr = oldstr.substr (0, oldstr.length() - 1);
4309 string base = Glib::path_get_dirname (oldstr);
4310 newstr = Glib::build_filename (base, legal_name);
4312 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4314 cerr << "Rename " << oldstr << " => " << newstr << endl;
4315 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4316 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4317 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4321 /* Reset path in "session dirs" */
4326 /* reset primary SessionDirectory object */
4329 (*_session_dir) = newstr;
4334 /* now rename directory below session_dir/interchange */
4336 string old_interchange_dir;
4337 string new_interchange_dir;
4339 /* use newstr here because we renamed the path
4340 * (folder/directory) that used to be oldstr to newstr above
4343 v.push_back (newstr);
4344 v.push_back (interchange_dir_name);
4345 v.push_back (Glib::path_get_basename (oldstr));
4347 old_interchange_dir = Glib::build_filename (v);
4350 v.push_back (newstr);
4351 v.push_back (interchange_dir_name);
4352 v.push_back (legal_name);
4354 new_interchange_dir = Glib::build_filename (v);
4356 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4358 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4359 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4360 old_interchange_dir, new_interchange_dir,
4363 error << string_compose (_("renaming %s as %2 failed (%3)"),
4364 old_interchange_dir, new_interchange_dir,
4373 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4374 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4376 cerr << "Rename " << oldstr << " => " << newstr << endl;
4378 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4379 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4380 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4386 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4388 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4389 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4391 cerr << "Rename " << oldstr << " => " << newstr << endl;
4393 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4394 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4395 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4400 /* remove old name from recent sessions */
4401 remove_recent_sessions (_path);
4404 /* update file source paths */
4406 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4407 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4409 string p = fs->path ();
4410 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4412 SourceFactory::setup_peakfile(i->second, true);
4416 set_snapshot_name (new_name);
4421 /* save state again to get everything just right */
4423 save_state (_current_snapshot_name);
4425 /* add to recent sessions */
4427 store_recent_sessions (new_name, _path);
4433 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4435 bool found_sr = false;
4436 bool found_data_format = false;
4437 program_version = "";
4439 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4443 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4447 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4450 xmlFreeParserCtxt(ctxt);
4454 xmlNodePtr node = xmlDocGetRootElement(doc);
4457 xmlFreeParserCtxt(ctxt);
4465 for (attr = node->properties; attr; attr = attr->next) {
4466 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4467 sample_rate = atoi ((char*)attr->children->content);
4472 node = node->children;
4473 while (node != NULL) {
4474 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4475 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4477 program_version = string ((const char*)val);
4478 size_t sep = program_version.find_first_of("-");
4479 if (sep != string::npos) {
4480 program_version = program_version.substr (0, sep);
4485 if (strcmp((const char*) node->name, "Config")) {
4489 for (node = node->children; node; node = node->next) {
4490 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4491 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4493 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4495 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4497 found_data_format = true;
4507 xmlFreeParserCtxt(ctxt);
4510 return !(found_sr && found_data_format); // zero if they are both found
4514 Session::get_snapshot_from_instant (const std::string& session_dir)
4516 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4518 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4523 if (!tree.read (instant_xml_path)) {
4527 XMLProperty const * prop;
4528 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4529 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4530 return prop->value();
4536 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4537 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4540 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4544 SourcePathMap source_path_map;
4546 boost::shared_ptr<AudioFileSource> afs;
4551 Glib::Threads::Mutex::Lock lm (source_lock);
4553 cerr << " total sources = " << sources.size();
4555 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4556 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4562 if (fs->within_session()) {
4566 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4567 source_path_map[fs->path()].push_back (fs);
4569 SeveralFileSources v;
4571 source_path_map.insert (make_pair (fs->path(), v));
4577 cerr << " fsources = " << total << endl;
4579 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4581 /* tell caller where we are */
4583 string old_path = i->first;
4585 callback (n, total, old_path);
4587 cerr << old_path << endl;
4591 switch (i->second.front()->type()) {
4592 case DataType::AUDIO:
4593 new_path = new_audio_source_path_for_embedded (old_path);
4596 case DataType::MIDI:
4597 /* XXX not implemented yet */
4601 if (new_path.empty()) {
4605 cerr << "Move " << old_path << " => " << new_path << endl;
4607 if (!copy_file (old_path, new_path)) {
4608 cerr << "failed !\n";
4612 /* make sure we stop looking in the external
4613 dir/folder. Remember, this is an all-or-nothing
4614 operations, it doesn't merge just some files.
4616 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4618 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4619 (*f)->set_path (new_path);
4624 save_state ("", false, false);
4630 bool accept_all_files (string const &, void *)
4636 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4638 /* 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.
4643 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4645 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4647 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4649 v.push_back (new_session_folder); /* full path */
4650 v.push_back (interchange_dir_name);
4651 v.push_back (new_session_path); /* just one directory/folder */
4652 v.push_back (typedir);
4653 v.push_back (Glib::path_get_basename (old_path));
4655 return Glib::build_filename (v);
4659 Session::save_as (SaveAs& saveas)
4661 vector<string> files;
4662 string current_folder = Glib::path_get_dirname (_path);
4663 string new_folder = legalize_for_path (saveas.new_name);
4664 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4665 int64_t total_bytes = 0;
4669 int32_t internal_file_cnt = 0;
4671 vector<string> do_not_copy_extensions;
4672 do_not_copy_extensions.push_back (statefile_suffix);
4673 do_not_copy_extensions.push_back (pending_suffix);
4674 do_not_copy_extensions.push_back (backup_suffix);
4675 do_not_copy_extensions.push_back (temp_suffix);
4676 do_not_copy_extensions.push_back (history_suffix);
4678 /* get total size */
4680 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4682 /* need to clear this because
4683 * find_files_matching_filter() is cumulative
4688 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4690 all += files.size();
4692 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4694 g_stat ((*i).c_str(), &gsb);
4695 total_bytes += gsb.st_size;
4699 /* save old values so we can switch back if we are not switching to the new session */
4701 string old_path = _path;
4702 string old_name = _name;
4703 string old_snapshot = _current_snapshot_name;
4704 string old_sd = _session_dir->root_path();
4705 vector<string> old_search_path[DataType::num_types];
4706 string old_config_search_path[DataType::num_types];
4708 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4709 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4710 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4711 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4713 /* switch session directory */
4715 (*_session_dir) = to_dir;
4717 /* create new tree */
4719 if (!_session_dir->create()) {
4720 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4725 /* copy all relevant files. Find each location in session_dirs,
4726 * and copy files from there to target.
4729 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4731 /* need to clear this because
4732 * find_files_matching_filter() is cumulative
4737 const size_t prefix_len = (*sd).path.size();
4739 /* Work just on the files within this session dir */
4741 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4743 /* add dir separator to protect against collisions with
4744 * track names (e.g. track named "audiofiles" or
4748 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4749 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4750 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4752 /* copy all the files. Handling is different for media files
4753 than others because of the *silly* subtree we have below the interchange
4754 folder. That really was a bad idea, but I'm not fixing it as part of
4755 implementing ::save_as().
4758 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4760 std::string from = *i;
4763 string filename = Glib::path_get_basename (from);
4764 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4765 if (filename == ".DS_STORE") {
4770 if (from.find (audiofile_dir_string) != string::npos) {
4772 /* audio file: only copy if asked */
4774 if (saveas.include_media && saveas.copy_media) {
4776 string to = make_new_media_path (*i, to_dir, new_folder);
4778 info << "media file copying from " << from << " to " << to << endmsg;
4780 if (!copy_file (from, to)) {
4781 throw Glib::FileError (Glib::FileError::IO_ERROR,
4782 string_compose(_("\ncopying \"%1\" failed !"), from));
4786 /* we found media files inside the session folder */
4788 internal_file_cnt++;
4790 } else if (from.find (midifile_dir_string) != string::npos) {
4792 /* midi file: always copy unless
4793 * creating an empty new session
4796 if (saveas.include_media) {
4798 string to = make_new_media_path (*i, to_dir, new_folder);
4800 info << "media file copying from " << from << " to " << to << endmsg;
4802 if (!copy_file (from, to)) {
4803 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4807 /* we found media files inside the session folder */
4809 internal_file_cnt++;
4811 } else if (from.find (analysis_dir_string) != string::npos) {
4813 /* make sure analysis dir exists in
4814 * new session folder, but we're not
4815 * copying analysis files here, see
4819 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4824 /* normal non-media file. Don't copy state, history, etc.
4827 bool do_copy = true;
4829 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4830 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4831 /* end of filename matches extension, do not copy file */
4837 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4838 /* don't copy peakfiles if
4839 * we're not copying media
4845 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4847 info << "attempting to make directory/folder " << to << endmsg;
4849 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4850 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4853 info << "attempting to copy " << from << " to " << to << endmsg;
4855 if (!copy_file (from, to)) {
4856 throw Glib::FileError (Glib::FileError::IO_ERROR,
4857 string_compose(_("\ncopying \"%1\" failed !"), from));
4862 /* measure file size even if we're not going to copy so that our Progress
4863 signals are correct, since we included these do-not-copy files
4864 in the computation of the total size and file count.
4868 g_stat (from.c_str(), &gsb);
4869 copied += gsb.st_size;
4872 double fraction = (double) copied / total_bytes;
4874 bool keep_going = true;
4876 if (saveas.copy_media) {
4878 /* no need or expectation of this if
4879 * media is not being copied, because
4880 * it will be fast(ish).
4883 /* tell someone "X percent, file M of N"; M is one-based */
4885 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4893 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4899 /* copy optional folders, if any */
4901 string old = plugins_dir ();
4902 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4903 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4904 copy_files (old, newdir);
4907 old = externals_dir ();
4908 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4909 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4910 copy_files (old, newdir);
4913 old = automation_dir ();
4914 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4915 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4916 copy_files (old, newdir);
4919 if (saveas.include_media) {
4921 if (saveas.copy_media) {
4922 #ifndef PLATFORM_WINDOWS
4923 /* There are problems with analysis files on
4924 * Windows, because they used a colon in their
4925 * names as late as 4.0. Colons are not legal
4926 * under Windows even if NTFS allows them.
4928 * This is a tricky problem to solve so for
4929 * just don't copy these files. They will be
4930 * regenerated as-needed anyway, subject to the
4931 * existing issue that the filenames will be
4932 * rejected by Windows, which is a separate
4933 * problem (though related).
4936 /* only needed if we are copying media, since the
4937 * analysis data refers to media data
4940 old = analysis_dir ();
4941 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4942 string newdir = Glib::build_filename (to_dir, "analysis");
4943 copy_files (old, newdir);
4945 #endif /* PLATFORM_WINDOWS */
4950 set_snapshot_name (saveas.new_name);
4951 _name = saveas.new_name;
4953 if (saveas.include_media && !saveas.copy_media) {
4955 /* reset search paths of the new session (which we're pretending to be right now) to
4956 include the original session search path, so we can still find all audio.
4959 if (internal_file_cnt) {
4960 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4961 ensure_search_path_includes (*s, DataType::AUDIO);
4962 cerr << "be sure to include " << *s << " for audio" << endl;
4965 /* we do not do this for MIDI because we copy
4966 all MIDI files if saveas.include_media is
4972 bool was_dirty = dirty ();
4974 save_default_options ();
4976 if (saveas.copy_media && saveas.copy_external) {
4977 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4978 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4982 saveas.final_session_folder_name = _path;
4984 store_recent_sessions (_name, _path);
4986 if (!saveas.switch_to) {
4988 /* save the new state */
4990 save_state ("", false, false, !saveas.include_media);
4992 /* switch back to the way things were */
4996 set_snapshot_name (old_snapshot);
4998 (*_session_dir) = old_sd;
5004 if (internal_file_cnt) {
5005 /* reset these to their original values */
5006 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5007 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5012 /* prune session dirs, and update disk space statistics
5017 session_dirs.clear ();
5018 session_dirs.push_back (sp);
5019 refresh_disk_space ();
5021 /* ensure that all existing tracks reset their current capture source paths
5023 reset_write_sources (true, true);
5025 /* creating new write sources marks the session as
5026 dirty. If the new session is empty, then
5027 save_state() thinks we're saving a template and will
5028 not mark the session as clean. So do that here,
5029 before we save state.
5032 if (!saveas.include_media) {
5033 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5036 save_state ("", false, false, !saveas.include_media);
5038 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5039 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5042 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5043 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5049 if (fs->within_session()) {
5050 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5051 fs->set_path (newpath);
5056 } catch (Glib::FileError& e) {
5058 saveas.failure_message = e.what();
5060 /* recursively remove all the directories */
5062 remove_directory (to_dir);
5070 saveas.failure_message = _("unknown reason");
5072 /* recursively remove all the directories */
5074 remove_directory (to_dir);
5084 static void set_progress (Progress* p, size_t n, size_t t)
5086 p->set_progress (float (n) / float(t));
5090 Session::archive_session (const std::string& dest,
5091 const std::string& name,
5092 ArchiveEncode compress_audio,
5093 bool only_used_sources,
5096 if (dest.empty () || name.empty ()) {
5100 /* save current values */
5101 bool was_dirty = dirty ();
5102 string old_path = _path;
5103 string old_name = _name;
5104 string old_snapshot = _current_snapshot_name;
5105 string old_sd = _session_dir->root_path();
5106 string old_config_search_path[DataType::num_types];
5107 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5108 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5110 /* ensure that session-path is included in search-path */
5112 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5113 if ((*sd).path == old_path) {
5121 /* create temporary dir to save session to */
5122 #ifdef PLATFORM_WINDOWS
5123 char tmp[256] = "C:\\TEMP\\";
5124 GetTempPath (sizeof (tmp), tmp);
5126 char const* tmp = getenv("TMPDIR");
5131 if ((strlen (tmp) + 21) > 1024) {
5136 strcpy (tmptpl, tmp);
5137 strcat (tmptpl, "ardourarchive-XXXXXX");
5138 char* tmpdir = g_mkdtemp (tmptpl);
5144 std::string to_dir = std::string (tmpdir);
5146 /* switch session directory temporarily */
5147 (*_session_dir) = to_dir;
5149 if (!_session_dir->create()) {
5150 (*_session_dir) = old_sd;
5151 remove_directory (to_dir);
5155 /* prepare archive */
5156 string archive = Glib::build_filename (dest, name + ".tar.xz");
5158 PBD::ScopedConnectionList progress_connection;
5159 PBD::FileArchive ar (archive);
5161 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5164 /* collect files to archive */
5165 std::map<string,string> filemap;
5167 vector<string> do_not_copy_extensions;
5168 do_not_copy_extensions.push_back (statefile_suffix);
5169 do_not_copy_extensions.push_back (pending_suffix);
5170 do_not_copy_extensions.push_back (backup_suffix);
5171 do_not_copy_extensions.push_back (temp_suffix);
5172 do_not_copy_extensions.push_back (history_suffix);
5174 vector<string> blacklist_dirs;
5175 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5176 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5177 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5178 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5179 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5180 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5182 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5183 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5185 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5186 if (only_used_sources) {
5187 playlists->sync_all_regions_with_regions ();
5188 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5191 // collect audio sources for this session, calc total size for encoding
5192 // add option to only include *used* sources (see Session::cleanup_sources)
5193 size_t total_size = 0;
5195 Glib::Threads::Mutex::Lock lm (source_lock);
5196 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5197 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5198 if (!afs || afs->readable_length () == 0) {
5202 if (only_used_sources) {
5206 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5211 std::string from = afs->path();
5213 if (compress_audio != NO_ENCODE) {
5214 total_size += afs->readable_length ();
5216 if (afs->within_session()) {
5217 filemap[from] = make_new_media_path (from, name, name);
5219 filemap[from] = make_new_media_path (from, name, name);
5220 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5227 if (compress_audio != NO_ENCODE) {
5229 progress->set_progress (2); // set to "encoding"
5230 progress->set_progress (0);
5233 Glib::Threads::Mutex::Lock lm (source_lock);
5234 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5235 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5236 if (!afs || afs->readable_length () == 0) {
5240 if (only_used_sources) {
5244 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5249 orig_sources[afs] = afs->path();
5250 orig_gain[afs] = afs->gain();
5252 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5253 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5254 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5257 progress->descend ((float)afs->readable_length () / total_size);
5261 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5262 afs->replace_file (new_path);
5263 afs->set_gain (ns->gain(), true);
5266 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5270 progress->ascend ();
5276 progress->set_progress (-1); // set to "archiving"
5277 progress->set_progress (0);
5280 /* index files relevant for this session */
5281 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5282 vector<string> files;
5284 size_t prefix_len = (*sd).path.size();
5285 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5289 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5291 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5292 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5293 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5295 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5296 std::string from = *i;
5299 string filename = Glib::path_get_basename (from);
5300 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5301 if (filename == ".DS_STORE") {
5306 if (from.find (audiofile_dir_string) != string::npos) {
5308 } else if (from.find (midifile_dir_string) != string::npos) {
5309 filemap[from] = make_new_media_path (from, name, name);
5310 } else if (from.find (videofile_dir_string) != string::npos) {
5311 filemap[from] = make_new_media_path (from, name, name);
5313 bool do_copy = true;
5314 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5315 if (from.find (*v) != string::npos) {
5320 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5321 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5328 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5334 /* write session file */
5336 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5338 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5341 save_default_options ();
5343 size_t prefix_len = _path.size();
5344 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5348 /* collect session-state files */
5349 vector<string> files;
5350 do_not_copy_extensions.clear ();
5351 do_not_copy_extensions.push_back (history_suffix);
5353 blacklist_dirs.clear ();
5354 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5356 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5357 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5358 std::string from = *i;
5359 bool do_copy = true;
5360 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5361 if (from.find (*v) != string::npos) {
5366 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5367 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5373 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5377 /* restore original values */
5380 set_snapshot_name (old_snapshot);
5381 (*_session_dir) = old_sd;
5385 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5386 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5388 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5389 i->first->replace_file (i->second);
5391 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5392 i->first->set_gain (i->second, true);
5395 int rv = ar.create (filemap);
5396 remove_directory (to_dir);
5402 Session::undo (uint32_t n)
5404 if (actively_recording()) {
5412 Session::redo (uint32_t n)
5414 if (actively_recording()) {