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_utils.h"
70 #include "pbd/pathexpand.h"
71 #include "pbd/pthread_utils.h"
72 #include "pbd/stacktrace.h"
73 #include "pbd/convert.h"
74 #include "pbd/localtime_r.h"
75 #include "pbd/unwind.h"
77 #include "ardour/amp.h"
78 #include "ardour/async_midi_port.h"
79 #include "ardour/audio_diskstream.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/auditioner.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/boost_debug.h"
87 #include "ardour/butler.h"
88 #include "ardour/controllable_descriptor.h"
89 #include "ardour/control_protocol_manager.h"
90 #include "ardour/directory_names.h"
91 #include "ardour/filename_extensions.h"
92 #include "ardour/graph.h"
93 #include "ardour/location.h"
94 #include "ardour/midi_model.h"
95 #include "ardour/midi_patch_manager.h"
96 #include "ardour/midi_region.h"
97 #include "ardour/midi_scene_changer.h"
98 #include "ardour/midi_source.h"
99 #include "ardour/midi_track.h"
100 #include "ardour/pannable.h"
101 #include "ardour/playlist_factory.h"
102 #include "ardour/playlist_source.h"
103 #include "ardour/port.h"
104 #include "ardour/processor.h"
105 #include "ardour/profile.h"
106 #include "ardour/proxy_controllable.h"
107 #include "ardour/recent_sessions.h"
108 #include "ardour/region_factory.h"
109 #include "ardour/revision.h"
110 #include "ardour/route_group.h"
111 #include "ardour/send.h"
112 #include "ardour/session.h"
113 #include "ardour/session_directory.h"
114 #include "ardour/session_metadata.h"
115 #include "ardour/session_playlists.h"
116 #include "ardour/session_state_utils.h"
117 #include "ardour/silentfilesource.h"
118 #include "ardour/sndfilesource.h"
119 #include "ardour/source_factory.h"
120 #include "ardour/speakers.h"
121 #include "ardour/template_utils.h"
122 #include "ardour/tempo.h"
123 #include "ardour/ticker.h"
124 #include "ardour/user_bundle.h"
125 #include "ardour/vca.h"
126 #include "ardour/vca_manager.h"
128 #include "control_protocol/control_protocol.h"
130 #include "LuaBridge/LuaBridge.h"
132 #include "pbd/i18n.h"
136 using namespace ARDOUR;
139 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
142 Session::pre_engine_init (string fullpath)
144 if (fullpath.empty()) {
146 throw failed_constructor();
149 /* discover canonical fullpath */
151 _path = canonical_path(fullpath);
154 if (Profile->get_trx() ) {
155 // Waves TracksLive has a usecase of session replacement with a new one.
156 // We should check session state file (<session_name>.ardour) existance
157 // to determine if the session is new or not
159 string full_session_name = Glib::build_filename( fullpath, _name );
160 full_session_name += statefile_suffix;
162 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
164 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
167 /* finish initialization that can't be done in a normal C++ constructor
171 timerclear (&last_mmc_step);
172 g_atomic_int_set (&processing_prohibited, 0);
173 g_atomic_int_set (&_record_status, Disabled);
174 g_atomic_int_set (&_playback_load, 100);
175 g_atomic_int_set (&_capture_load, 100);
177 _all_route_group->set_active (true, this);
178 interpolation.add_channel_to (0, 0);
180 if (config.get_use_video_sync()) {
181 waiting_for_sync_offset = true;
183 waiting_for_sync_offset = false;
186 last_rr_session_dir = session_dirs.begin();
188 set_history_depth (Config->get_history_depth());
190 /* default: assume simple stereo speaker configuration */
192 _speakers->setup_default_speakers (2);
194 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
195 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
196 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
197 add_controllable (_solo_cut_control);
199 /* These are all static "per-class" signals */
201 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
202 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
203 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
204 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
205 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
207 /* stop IO objects from doing stuff until we're ready for them */
209 Delivery::disable_panners ();
210 IO::disable_connecting ();
214 Session::post_engine_init ()
216 BootMessage (_("Set block size and sample rate"));
218 set_block_size (_engine.samples_per_cycle());
219 set_frame_rate (_engine.sample_rate());
221 BootMessage (_("Using configuration"));
223 _midi_ports = new MidiPortManager;
225 MIDISceneChanger* msc;
227 _scene_changer = msc = new MIDISceneChanger (*this);
228 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
229 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
231 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
232 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
234 setup_midi_machine_control ();
236 if (_butler->start_thread()) {
240 if (start_midi_thread ()) {
244 setup_click_sounds (0);
245 setup_midi_control ();
247 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
248 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
251 /* tempo map requires sample rate knowledge */
254 _tempo_map = new TempoMap (_current_frame_rate);
255 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
256 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
258 /* MidiClock requires a tempo map */
261 midi_clock = new MidiClockTicker ();
262 midi_clock->set_session (this);
264 /* crossfades require sample rate knowledge */
266 SndFileSource::setup_standard_crossfades (*this, frame_rate());
267 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
269 AudioDiskstream::allocate_working_buffers();
270 refresh_disk_space ();
272 /* we're finally ready to call set_state() ... all objects have
273 * been created, the engine is running.
277 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
281 // set_state() will call setup_raid_path(), but if it's a new session we need
282 // to call setup_raid_path() here.
283 setup_raid_path (_path);
288 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
289 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
291 Config->map_parameters (ff);
292 config.map_parameters (ft);
293 _butler->map_parameters ();
295 /* Reset all panners */
297 Delivery::reset_panners ();
299 /* this will cause the CPM to instantiate any protocols that are in use
300 * (or mandatory), which will pass it this Session, and then call
301 * set_state() on each instantiated protocol to match stored state.
304 ControlProtocolManager::instance().set_session (this);
306 /* This must be done after the ControlProtocolManager set_session above,
307 as it will set states for ports which the ControlProtocolManager creates.
310 // XXX set state of MIDI::Port's
311 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
313 /* And this must be done after the MIDI::Manager::set_port_states as
314 * it will try to make connections whose details are loaded by set_port_states.
319 /* Let control protocols know that we are now all connected, so they
320 * could start talking to surfaces if they want to.
323 ControlProtocolManager::instance().midi_connectivity_established ();
325 if (_is_new && !no_auto_connect()) {
326 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
327 auto_connect_master_bus ();
330 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
332 /* update latencies */
334 initialize_latencies ();
336 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
337 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
338 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
340 } catch (AudioEngine::PortRegistrationFailure& err) {
341 /* handle this one in a different way than all others, so that its clear what happened */
342 error << err.what() << endmsg;
348 BootMessage (_("Reset Remote Controls"));
350 // send_full_time_code (0);
351 _engine.transport_locate (0);
353 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
354 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
356 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
359 /* initial program change will be delivered later; see ::config_changed() */
361 _state_of_the_state = Clean;
363 Port::set_connecting_blocked (false);
365 DirtyChanged (); /* EMIT SIGNAL */
369 } else if (state_was_pending) {
371 remove_pending_capture_state ();
372 state_was_pending = false;
375 /* Now, finally, we can fill the playback buffers */
377 BootMessage (_("Filling playback buffers"));
379 boost::shared_ptr<RouteList> rl = routes.reader();
380 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
381 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
382 if (trk && !trk->hidden()) {
383 trk->seek (_transport_frame, true);
391 Session::session_loaded ()
395 _state_of_the_state = Clean;
397 DirtyChanged (); /* EMIT SIGNAL */
401 } else if (state_was_pending) {
403 remove_pending_capture_state ();
404 state_was_pending = false;
407 /* Now, finally, we can fill the playback buffers */
409 BootMessage (_("Filling playback buffers"));
410 force_locate (_transport_frame, false);
414 Session::raid_path () const
416 Searchpath raid_search_path;
418 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
419 raid_search_path += (*i).path;
422 return raid_search_path.to_string ();
426 Session::setup_raid_path (string path)
435 session_dirs.clear ();
437 Searchpath search_path(path);
438 Searchpath sound_search_path;
439 Searchpath midi_search_path;
441 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
443 sp.blocks = 0; // not needed
444 session_dirs.push_back (sp);
446 SessionDirectory sdir(sp.path);
448 sound_search_path += sdir.sound_path ();
449 midi_search_path += sdir.midi_path ();
452 // reset the round-robin soundfile path thingie
453 last_rr_session_dir = session_dirs.begin();
457 Session::path_is_within_session (const std::string& path)
459 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
460 if (PBD::path_is_within (i->path, path)) {
468 Session::ensure_subdirs ()
472 dir = session_directory().peak_path();
474 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
475 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
479 dir = session_directory().sound_path();
481 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
482 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
486 dir = session_directory().midi_path();
488 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
489 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
493 dir = session_directory().dead_path();
495 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
496 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
500 dir = session_directory().export_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = analysis_dir ();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = plugins_dir ();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = externals_dir ();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 /** @param session_template directory containing session template, or empty.
532 * Caller must not hold process lock.
535 Session::create (const string& session_template, BusProfile* bus_profile)
537 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
542 if (ensure_subdirs ()) {
546 _writable = exists_and_writable (_path);
548 if (!session_template.empty()) {
549 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
551 FILE* in = g_fopen (in_path.c_str(), "rb");
554 /* no need to call legalize_for_path() since the string
555 * in session_template is already a legal path name
557 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
559 FILE* out = g_fopen (out_path.c_str(), "wb");
563 stringstream new_session;
566 size_t charsRead = fread (buf, sizeof(char), 1024, in);
569 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
574 if (charsRead == 0) {
577 new_session.write (buf, charsRead);
581 string file_contents = new_session.str();
582 size_t writeSize = file_contents.length();
583 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
584 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
592 if (!ARDOUR::Profile->get_trx()) {
593 /* Copy plugin state files from template to new session */
594 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
595 copy_recurse (template_plugins, plugins_dir ());
601 error << string_compose (_("Could not open %1 for writing session template"), out_path)
608 error << string_compose (_("Could not open session template %1 for reading"), in_path)
615 if (Profile->get_trx()) {
617 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
618 Remember that this is a brand new session. Sessions
619 loaded from saved state will get this range from the saved state.
622 set_session_range_location (0, 0);
624 /* Initial loop location, from absolute zero, length 10 seconds */
626 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
627 _locations->add (loc, true);
628 set_auto_loop_location (loc);
631 _state_of_the_state = Clean;
633 /* set up Master Out and Monitor Out if necessary */
638 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
640 // Waves Tracks: always create master bus for Tracks
641 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
642 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
650 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
651 r->input()->ensure_io (count, false, this);
652 r->output()->ensure_io (count, false, this);
658 /* prohibit auto-connect to master, because there isn't one */
659 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
663 add_routes (rl, false, false, false, PresentationInfo::max_order);
666 // Waves Tracks: Skip this. Always use autoconnection for Tracks
667 if (!ARDOUR::Profile->get_trx()) {
669 /* this allows the user to override settings with an environment variable.
672 if (no_auto_connect()) {
673 bus_profile->input_ac = AutoConnectOption (0);
674 bus_profile->output_ac = AutoConnectOption (0);
677 Config->set_input_auto_connect (bus_profile->input_ac);
678 Config->set_output_auto_connect (bus_profile->output_ac);
682 if (Config->get_use_monitor_bus() && bus_profile) {
683 add_monitor_section ();
690 Session::maybe_write_autosave()
692 if (dirty() && record_status() != Recording) {
693 save_state("", true);
698 Session::remove_pending_capture_state ()
700 std::string pending_state_file_path(_session_dir->root_path());
702 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
704 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
706 if (g_remove (pending_state_file_path.c_str()) != 0) {
707 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
708 pending_state_file_path, g_strerror (errno)) << endmsg;
712 /** Rename a state file.
713 * @param old_name Old snapshot name.
714 * @param new_name New snapshot name.
717 Session::rename_state (string old_name, string new_name)
719 if (old_name == _current_snapshot_name || old_name == _name) {
720 /* refuse to rename the current snapshot or the "main" one */
724 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
725 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
727 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
728 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
730 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
731 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
732 old_name, new_name, g_strerror(errno)) << endmsg;
736 /** Remove a state file.
737 * @param snapshot_name Snapshot name.
740 Session::remove_state (string snapshot_name)
742 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
743 // refuse to remove the current snapshot or the "main" one
747 std::string xml_path(_session_dir->root_path());
749 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
751 if (!create_backup_file (xml_path)) {
752 // don't remove it if a backup can't be made
753 // create_backup_file will log the error.
758 if (g_remove (xml_path.c_str()) != 0) {
759 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
760 xml_path, g_strerror (errno)) << endmsg;
764 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
766 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
768 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
771 std::string xml_path(_session_dir->root_path());
773 /* prevent concurrent saves from different threads */
775 Glib::Threads::Mutex::Lock lm (save_state_lock);
777 if (!_writable || (_state_of_the_state & CannotSave)) {
781 if (g_atomic_int_get(&_suspend_save)) {
785 _save_queued = false;
787 if (!_engine.connected ()) {
788 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
795 const int64_t save_start_time = g_get_monotonic_time();
798 /* tell sources we're saving first, in case they write out to a new file
799 * which should be saved with the state rather than the old one */
800 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
802 i->second->session_saved();
803 } catch (Evoral::SMF::FileError& e) {
804 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
808 SessionSaveUnderway (); /* EMIT SIGNAL */
810 bool mark_as_clean = true;
812 if (!snapshot_name.empty() && !switch_to_snapshot) {
813 mark_as_clean = false;
817 mark_as_clean = false;
818 tree.set_root (&get_template());
820 tree.set_root (&get_state());
823 if (snapshot_name.empty()) {
824 snapshot_name = _current_snapshot_name;
825 } else if (switch_to_snapshot) {
826 set_snapshot_name (snapshot_name);
829 assert (!snapshot_name.empty());
833 /* proper save: use statefile_suffix (.ardour in English) */
835 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
837 /* make a backup copy of the old file */
839 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
840 // create_backup_file will log the error
846 /* pending save: use pending_suffix (.pending in English) */
847 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
850 std::string tmp_path(_session_dir->root_path());
851 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
853 cerr << "actually writing state to " << tmp_path << endl;
855 if (!tree.write (tmp_path)) {
856 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
857 if (g_remove (tmp_path.c_str()) != 0) {
858 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
859 tmp_path, g_strerror (errno)) << endmsg;
865 cerr << "renaming state to " << xml_path << endl;
867 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
868 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
869 tmp_path, xml_path, g_strerror(errno)) << 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;
880 save_history (snapshot_name);
883 bool was_dirty = dirty();
885 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
888 DirtyChanged (); /* EMIT SIGNAL */
892 StateSaved (snapshot_name); /* EMIT SIGNAL */
896 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
897 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
903 Session::restore_state (string snapshot_name)
905 if (load_state (snapshot_name) == 0) {
906 set_state (*state_tree->root(), Stateful::loading_state_version);
913 Session::load_state (string snapshot_name)
918 state_was_pending = false;
920 /* check for leftover pending state from a crashed capture attempt */
922 std::string xmlpath(_session_dir->root_path());
923 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
925 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
927 /* there is pending state from a crashed capture attempt */
929 boost::optional<int> r = AskAboutPendingState();
930 if (r.get_value_or (1)) {
931 state_was_pending = true;
935 if (!state_was_pending) {
936 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
939 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
941 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
942 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
947 state_tree = new XMLTree;
951 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
953 if (!state_tree->read (xmlpath)) {
954 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
960 XMLNode const & root (*state_tree->root());
962 if (root.name() != X_("Session")) {
963 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
969 XMLProperty const * prop;
971 if ((prop = root.property ("version")) == 0) {
972 /* no version implies very old version of Ardour */
973 Stateful::loading_state_version = 1000;
975 if (prop->value().find ('.') != string::npos) {
976 /* old school version format */
977 if (prop->value()[0] == '2') {
978 Stateful::loading_state_version = 2000;
980 Stateful::loading_state_version = 3000;
983 Stateful::loading_state_version = atoi (prop->value());
987 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
989 std::string backup_path(_session_dir->root_path());
990 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
991 backup_path = Glib::build_filename (backup_path, backup_filename);
993 // only create a backup for a given statefile version once
995 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
997 VersionMismatch (xmlpath, backup_path);
999 if (!copy_file (xmlpath, backup_path)) {;
1005 if ((child = find_named_node (root, "ProgramVersion")) != 0) {
1006 if ((prop = child->property ("modified-with")) != 0) {
1007 std::string modified_with = prop->value ();
1009 const double modified_with_version = atof (modified_with.substr ( modified_with.find(" ", 0) + 1, string::npos).c_str());
1010 const int modified_with_revision = atoi (modified_with.substr (modified_with.find("-", 0) + 1, string::npos).c_str());
1012 if (modified_with_version <= 5.3 && !(modified_with_version == 5.3 && modified_with_revision > 42)) {
1013 _midi_regions_use_bbt_beats = true;
1019 save_snapshot_name (snapshot_name);
1025 Session::load_options (const XMLNode& node)
1028 config.set_variables (node);
1033 Session::save_default_options ()
1035 return config.save_state();
1039 Session::get_state()
1045 Session::get_template()
1047 /* if we don't disable rec-enable, diskstreams
1048 will believe they need to store their capture
1049 sources in their state node.
1052 disable_record (false);
1054 return state(false);
1058 Session::state (bool full_state)
1061 XMLNode* node = new XMLNode("Session");
1065 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1066 node->add_property("version", buf);
1068 child = node->add_child ("ProgramVersion");
1069 child->add_property("created-with", created_with);
1071 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1072 child->add_property("modified-with", modified_with);
1074 /* store configuration settings */
1078 node->add_property ("name", _name);
1079 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1080 node->add_property ("sample-rate", buf);
1082 if (session_dirs.size() > 1) {
1086 vector<space_and_path>::iterator i = session_dirs.begin();
1087 vector<space_and_path>::iterator next;
1089 ++i; /* skip the first one */
1093 while (i != session_dirs.end()) {
1097 if (next != session_dirs.end()) {
1098 p += G_SEARCHPATH_SEPARATOR;
1107 child = node->add_child ("Path");
1108 child->add_content (p);
1112 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1114 /* save the ID counter */
1116 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1117 node->add_property ("id-counter", buf);
1119 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1120 node->add_property ("name-counter", buf);
1122 /* save the event ID counter */
1124 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1125 node->add_property ("event-counter", buf);
1127 /* save the VCA counter */
1129 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1130 node->add_property ("vca-counter", buf);
1132 /* various options */
1134 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1135 if (!midi_port_nodes.empty()) {
1136 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1137 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1138 midi_port_stuff->add_child_nocopy (**n);
1140 node->add_child_nocopy (*midi_port_stuff);
1143 node->add_child_nocopy (config.get_variables ());
1145 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1147 child = node->add_child ("Sources");
1150 Glib::Threads::Mutex::Lock sl (source_lock);
1152 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1154 /* Don't save information about non-file Sources, or
1155 * about non-destructive file sources that are empty
1156 * and unused by any regions.
1159 boost::shared_ptr<FileSource> fs;
1161 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1163 if (!fs->destructive()) {
1164 if (fs->empty() && !fs->used()) {
1169 child->add_child_nocopy (siter->second->get_state());
1174 child = node->add_child ("Regions");
1177 Glib::Threads::Mutex::Lock rl (region_lock);
1178 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1179 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1180 boost::shared_ptr<Region> r = i->second;
1181 /* only store regions not attached to playlists */
1182 if (r->playlist() == 0) {
1183 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1184 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1186 child->add_child_nocopy (r->get_state ());
1191 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1193 if (!cassocs.empty()) {
1194 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1196 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1198 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1199 i->first->id().print (buf, sizeof (buf));
1200 can->add_property (X_("copy"), buf);
1201 i->second->id().print (buf, sizeof (buf));
1202 can->add_property (X_("original"), buf);
1203 ca->add_child_nocopy (*can);
1213 node->add_child_nocopy (_locations->get_state());
1216 Locations loc (*this);
1217 // for a template, just create a new Locations, populate it
1218 // with the default start and end, and get the state for that.
1219 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1220 range->set (max_framepos, 0);
1222 XMLNode& locations_state = loc.get_state();
1224 if (ARDOUR::Profile->get_trx() && _locations) {
1225 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1226 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1227 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1228 locations_state.add_child_nocopy ((*i)->get_state ());
1232 node->add_child_nocopy (locations_state);
1235 child = node->add_child ("Bundles");
1237 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1238 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1239 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1241 child->add_child_nocopy (b->get_state());
1246 node->add_child_nocopy (_vca_manager->get_state());
1248 child = node->add_child ("Routes");
1250 boost::shared_ptr<RouteList> r = routes.reader ();
1252 RoutePublicOrderSorter cmp;
1253 RouteList public_order (*r);
1254 public_order.sort (cmp);
1256 /* the sort should have put the monitor out first */
1259 assert (_monitor_out == public_order.front());
1262 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1263 if (!(*i)->is_auditioner()) {
1265 child->add_child_nocopy ((*i)->get_state());
1267 child->add_child_nocopy ((*i)->get_template());
1273 playlists->add_state (node, full_state);
1275 child = node->add_child ("RouteGroups");
1276 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1277 child->add_child_nocopy ((*i)->get_state());
1281 XMLNode* gain_child = node->add_child ("Click");
1282 gain_child->add_child_nocopy (_click_io->state (full_state));
1283 gain_child->add_child_nocopy (_click_gain->state (full_state));
1287 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1288 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1292 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1293 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1296 node->add_child_nocopy (_speakers->get_state());
1297 node->add_child_nocopy (_tempo_map->get_state());
1298 node->add_child_nocopy (get_control_protocol_state());
1301 node->add_child_copy (*_extra_xml);
1305 Glib::Threads::Mutex::Lock lm (lua_lock);
1308 luabridge::LuaRef savedstate ((*_lua_save)());
1309 saved = savedstate.cast<std::string>();
1311 lua.collect_garbage ();
1314 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1315 std::string b64s (b64);
1318 XMLNode* script_node = new XMLNode (X_("Script"));
1319 script_node->add_property (X_("lua"), LUA_VERSION);
1320 script_node->add_content (b64s);
1321 node->add_child_nocopy (*script_node);
1328 Session::get_control_protocol_state ()
1330 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1331 return cpm.get_state();
1335 Session::set_state (const XMLNode& node, int version)
1340 XMLProperty const * prop;
1343 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1345 if (node.name() != X_("Session")) {
1346 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1350 if ((prop = node.property ("name")) != 0) {
1351 _name = prop->value ();
1354 if ((prop = node.property (X_("sample-rate"))) != 0) {
1356 _base_frame_rate = atoi (prop->value());
1357 _nominal_frame_rate = _base_frame_rate;
1359 assert (AudioEngine::instance()->running ());
1360 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1361 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1362 if (r.get_value_or (0)) {
1368 created_with = "unknown";
1369 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1370 if ((prop = child->property (X_("created-with"))) != 0) {
1371 created_with = prop->value ();
1375 setup_raid_path(_session_dir->root_path());
1377 if ((prop = node.property (X_("end-is-free"))) != 0) {
1378 _session_range_end_is_free = string_is_affirmative (prop->value());
1381 if ((prop = node.property (X_("id-counter"))) != 0) {
1383 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1384 ID::init_counter (x);
1386 /* old sessions used a timebased counter, so fake
1387 the startup ID counter based on a standard
1392 ID::init_counter (now);
1395 if ((prop = node.property (X_("name-counter"))) != 0) {
1396 init_name_id_counter (atoi (prop->value()));
1399 if ((prop = node.property (X_("event-counter"))) != 0) {
1400 Evoral::init_event_id_counter (atoi (prop->value()));
1403 if ((prop = node.property (X_("vca-counter"))) != 0) {
1405 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1406 VCA::set_next_vca_number (x);
1408 VCA::set_next_vca_number (1);
1411 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1412 _midi_ports->set_midi_port_states (child->children());
1415 IO::disable_connecting ();
1417 Stateful::save_extra_xml (node);
1419 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1420 load_options (*child);
1421 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1422 load_options (*child);
1424 error << _("Session: XML state has no options section") << endmsg;
1427 if (version >= 3000) {
1428 if ((child = find_named_node (node, "Metadata")) == 0) {
1429 warning << _("Session: XML state has no metadata section") << endmsg;
1430 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1435 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1436 _speakers->set_state (*child, version);
1439 if ((child = find_named_node (node, "Sources")) == 0) {
1440 error << _("Session: XML state has no sources section") << endmsg;
1442 } else if (load_sources (*child)) {
1446 if ((child = find_named_node (node, "TempoMap")) == 0) {
1447 error << _("Session: XML state has no Tempo Map section") << endmsg;
1449 } else if (_tempo_map->set_state (*child, version)) {
1453 if ((child = find_named_node (node, "Locations")) == 0) {
1454 error << _("Session: XML state has no locations section") << endmsg;
1456 } else if (_locations->set_state (*child, version)) {
1460 locations_changed ();
1462 if (_session_range_location) {
1463 AudioFileSource::set_header_position_offset (_session_range_location->start());
1466 if ((child = find_named_node (node, "Regions")) == 0) {
1467 error << _("Session: XML state has no Regions section") << endmsg;
1469 } else if (load_regions (*child)) {
1473 if ((child = find_named_node (node, "Playlists")) == 0) {
1474 error << _("Session: XML state has no playlists section") << endmsg;
1476 } else if (playlists->load (*this, *child)) {
1480 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1482 } else if (playlists->load_unused (*this, *child)) {
1486 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1487 if (load_compounds (*child)) {
1492 if (version >= 3000) {
1493 if ((child = find_named_node (node, "Bundles")) == 0) {
1494 warning << _("Session: XML state has no bundles section") << endmsg;
1497 /* We can't load Bundles yet as they need to be able
1498 to convert from port names to Port objects, which can't happen until
1500 _bundle_xml_node = new XMLNode (*child);
1504 if (version < 3000) {
1505 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1506 error << _("Session: XML state has no diskstreams section") << endmsg;
1508 } else if (load_diskstreams_2X (*child, version)) {
1513 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1514 _vca_manager->set_state (*child, version);
1517 if ((child = find_named_node (node, "Routes")) == 0) {
1518 error << _("Session: XML state has no routes section") << endmsg;
1520 } else if (load_routes (*child, version)) {
1524 /* Now that we have Routes and masters loaded, connect them if appropriate */
1526 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1528 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1529 _diskstreams_2X.clear ();
1531 if (version >= 3000) {
1533 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1534 error << _("Session: XML state has no route groups section") << endmsg;
1536 } else if (load_route_groups (*child, version)) {
1540 } else if (version < 3000) {
1542 if ((child = find_named_node (node, "EditGroups")) == 0) {
1543 error << _("Session: XML state has no edit groups section") << endmsg;
1545 } else if (load_route_groups (*child, version)) {
1549 if ((child = find_named_node (node, "MixGroups")) == 0) {
1550 error << _("Session: XML state has no mix groups section") << endmsg;
1552 } else if (load_route_groups (*child, version)) {
1557 if ((child = find_named_node (node, "Click")) == 0) {
1558 warning << _("Session: XML state has no click section") << endmsg;
1559 } else if (_click_io) {
1560 setup_click_state (&node);
1563 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1564 ControlProtocolManager::instance().set_state (*child, version);
1567 if ((child = find_named_node (node, "Script"))) {
1568 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1569 if (!(*n)->is_content ()) { continue; }
1571 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1573 Glib::Threads::Mutex::Lock lm (lua_lock);
1574 (*_lua_load)(std::string ((const char*)buf, size));
1575 } catch (luabridge::LuaException const& e) {
1576 cerr << "LuaException:" << e.what () << endl;
1582 update_route_record_state ();
1584 /* here beginneth the second phase ... */
1585 set_snapshot_name (_current_snapshot_name);
1587 StateReady (); /* EMIT SIGNAL */
1600 Session::load_routes (const XMLNode& node, int version)
1603 XMLNodeConstIterator niter;
1604 RouteList new_routes;
1606 nlist = node.children();
1610 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1612 boost::shared_ptr<Route> route;
1613 if (version < 3000) {
1614 route = XMLRouteFactory_2X (**niter, version);
1616 route = XMLRouteFactory (**niter, version);
1620 error << _("Session: cannot create Route from XML description.") << endmsg;
1624 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1626 new_routes.push_back (route);
1629 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1631 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1633 BootMessage (_("Finished adding tracks/busses"));
1638 boost::shared_ptr<Route>
1639 Session::XMLRouteFactory (const XMLNode& node, int version)
1641 boost::shared_ptr<Route> ret;
1643 if (node.name() != "Route") {
1647 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1649 DataType type = DataType::AUDIO;
1650 XMLProperty const * prop = node.property("default-type");
1653 type = DataType (prop->value());
1656 assert (type != DataType::NIL);
1660 boost::shared_ptr<Track> track;
1662 if (type == DataType::AUDIO) {
1663 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1665 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1668 if (track->init()) {
1672 if (track->set_state (node, version)) {
1676 BOOST_MARK_TRACK (track);
1680 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1681 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1683 if (r->init () == 0 && r->set_state (node, version) == 0) {
1684 BOOST_MARK_ROUTE (r);
1692 boost::shared_ptr<Route>
1693 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1695 boost::shared_ptr<Route> ret;
1697 if (node.name() != "Route") {
1701 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1703 ds_prop = node.property (X_("diskstream"));
1706 DataType type = DataType::AUDIO;
1707 XMLProperty const * prop = node.property("default-type");
1710 type = DataType (prop->value());
1713 assert (type != DataType::NIL);
1717 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1718 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1722 if (i == _diskstreams_2X.end()) {
1723 error << _("Could not find diskstream for route") << endmsg;
1724 return boost::shared_ptr<Route> ();
1727 boost::shared_ptr<Track> track;
1729 if (type == DataType::AUDIO) {
1730 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1732 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1735 if (track->init()) {
1739 if (track->set_state (node, version)) {
1743 track->set_diskstream (*i);
1745 BOOST_MARK_TRACK (track);
1749 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1750 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1752 if (r->init () == 0 && r->set_state (node, version) == 0) {
1753 BOOST_MARK_ROUTE (r);
1762 Session::load_regions (const XMLNode& node)
1765 XMLNodeConstIterator niter;
1766 boost::shared_ptr<Region> region;
1768 nlist = node.children();
1772 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1773 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1774 error << _("Session: cannot create Region from XML description.");
1775 XMLProperty const * name = (**niter).property("name");
1778 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1789 Session::load_compounds (const XMLNode& node)
1791 XMLNodeList calist = node.children();
1792 XMLNodeConstIterator caiter;
1793 XMLProperty const * caprop;
1795 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1796 XMLNode* ca = *caiter;
1800 if ((caprop = ca->property (X_("original"))) == 0) {
1803 orig_id = caprop->value();
1805 if ((caprop = ca->property (X_("copy"))) == 0) {
1808 copy_id = caprop->value();
1810 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1811 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1813 if (!orig || !copy) {
1814 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1820 RegionFactory::add_compound_association (orig, copy);
1827 Session::load_nested_sources (const XMLNode& node)
1830 XMLNodeConstIterator niter;
1832 nlist = node.children();
1834 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1835 if ((*niter)->name() == "Source") {
1837 /* it may already exist, so don't recreate it unnecessarily
1840 XMLProperty const * prop = (*niter)->property (X_("id"));
1842 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1846 ID source_id (prop->value());
1848 if (!source_by_id (source_id)) {
1851 SourceFactory::create (*this, **niter, true);
1853 catch (failed_constructor& err) {
1854 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1861 boost::shared_ptr<Region>
1862 Session::XMLRegionFactory (const XMLNode& node, bool full)
1864 XMLProperty const * type = node.property("type");
1868 const XMLNodeList& nlist = node.children();
1870 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1871 XMLNode *child = (*niter);
1872 if (child->name() == "NestedSource") {
1873 load_nested_sources (*child);
1877 if (!type || type->value() == "audio") {
1878 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1879 } else if (type->value() == "midi") {
1880 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1883 } catch (failed_constructor& err) {
1884 return boost::shared_ptr<Region> ();
1887 return boost::shared_ptr<Region> ();
1890 boost::shared_ptr<AudioRegion>
1891 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1893 XMLProperty const * prop;
1894 boost::shared_ptr<Source> source;
1895 boost::shared_ptr<AudioSource> as;
1897 SourceList master_sources;
1898 uint32_t nchans = 1;
1901 if (node.name() != X_("Region")) {
1902 return boost::shared_ptr<AudioRegion>();
1905 if ((prop = node.property (X_("channels"))) != 0) {
1906 nchans = atoi (prop->value().c_str());
1909 if ((prop = node.property ("name")) == 0) {
1910 cerr << "no name for this region\n";
1914 if ((prop = node.property (X_("source-0"))) == 0) {
1915 if ((prop = node.property ("source")) == 0) {
1916 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1917 return boost::shared_ptr<AudioRegion>();
1921 PBD::ID s_id (prop->value());
1923 if ((source = source_by_id (s_id)) == 0) {
1924 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1925 return boost::shared_ptr<AudioRegion>();
1928 as = boost::dynamic_pointer_cast<AudioSource>(source);
1930 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1931 return boost::shared_ptr<AudioRegion>();
1934 sources.push_back (as);
1936 /* pickup other channels */
1938 for (uint32_t n=1; n < nchans; ++n) {
1939 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1940 if ((prop = node.property (buf)) != 0) {
1942 PBD::ID id2 (prop->value());
1944 if ((source = source_by_id (id2)) == 0) {
1945 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1946 return boost::shared_ptr<AudioRegion>();
1949 as = boost::dynamic_pointer_cast<AudioSource>(source);
1951 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1952 return boost::shared_ptr<AudioRegion>();
1954 sources.push_back (as);
1958 for (uint32_t n = 0; n < nchans; ++n) {
1959 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1960 if ((prop = node.property (buf)) != 0) {
1962 PBD::ID id2 (prop->value());
1964 if ((source = source_by_id (id2)) == 0) {
1965 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1966 return boost::shared_ptr<AudioRegion>();
1969 as = boost::dynamic_pointer_cast<AudioSource>(source);
1971 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1972 return boost::shared_ptr<AudioRegion>();
1974 master_sources.push_back (as);
1979 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1981 /* a final detail: this is the one and only place that we know how long missing files are */
1983 if (region->whole_file()) {
1984 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1985 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1987 sfp->set_length (region->length());
1992 if (!master_sources.empty()) {
1993 if (master_sources.size() != nchans) {
1994 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1996 region->set_master_sources (master_sources);
2004 catch (failed_constructor& err) {
2005 return boost::shared_ptr<AudioRegion>();
2009 boost::shared_ptr<MidiRegion>
2010 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2012 XMLProperty const * prop;
2013 boost::shared_ptr<Source> source;
2014 boost::shared_ptr<MidiSource> ms;
2017 if (node.name() != X_("Region")) {
2018 return boost::shared_ptr<MidiRegion>();
2021 if ((prop = node.property ("name")) == 0) {
2022 cerr << "no name for this region\n";
2026 if ((prop = node.property (X_("source-0"))) == 0) {
2027 if ((prop = node.property ("source")) == 0) {
2028 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2029 return boost::shared_ptr<MidiRegion>();
2033 PBD::ID s_id (prop->value());
2035 if ((source = source_by_id (s_id)) == 0) {
2036 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2037 return boost::shared_ptr<MidiRegion>();
2040 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2042 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2043 return boost::shared_ptr<MidiRegion>();
2046 sources.push_back (ms);
2049 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2050 /* a final detail: this is the one and only place that we know how long missing files are */
2052 if (region->whole_file()) {
2053 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2054 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2056 sfp->set_length (region->length());
2064 catch (failed_constructor& err) {
2065 return boost::shared_ptr<MidiRegion>();
2070 Session::get_sources_as_xml ()
2073 XMLNode* node = new XMLNode (X_("Sources"));
2074 Glib::Threads::Mutex::Lock lm (source_lock);
2076 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2077 node->add_child_nocopy (i->second->get_state());
2084 Session::reset_write_sources (bool mark_write_complete, bool force)
2086 boost::shared_ptr<RouteList> rl = routes.reader();
2087 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2088 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2090 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2091 tr->reset_write_sources(mark_write_complete, force);
2092 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2098 Session::load_sources (const XMLNode& node)
2101 XMLNodeConstIterator niter;
2102 boost::shared_ptr<Source> source; /* don't need this but it stops some
2103 * versions of gcc complaining about
2104 * discarded return values.
2107 nlist = node.children();
2111 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2114 if ((source = XMLSourceFactory (**niter)) == 0) {
2115 error << _("Session: cannot create Source from XML description.") << endmsg;
2118 } catch (MissingSource& err) {
2122 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2123 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2124 PROGRAM_NAME) << endmsg;
2128 if (!no_questions_about_missing_files) {
2129 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2134 switch (user_choice) {
2136 /* user added a new search location, so try again */
2141 /* user asked to quit the entire session load
2146 no_questions_about_missing_files = true;
2150 no_questions_about_missing_files = true;
2157 case DataType::AUDIO:
2158 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2161 case DataType::MIDI:
2162 /* The MIDI file is actually missing so
2163 * just create a new one in the same
2164 * location. Do not announce its
2168 if (!Glib::path_is_absolute (err.path)) {
2169 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2171 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2176 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2177 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2178 /* reset ID to match the missing one */
2179 source->set_id (**niter);
2180 /* Now we can announce it */
2181 SourceFactory::SourceCreated (source);
2192 boost::shared_ptr<Source>
2193 Session::XMLSourceFactory (const XMLNode& node)
2195 if (node.name() != "Source") {
2196 return boost::shared_ptr<Source>();
2200 /* note: do peak building in another thread when loading session state */
2201 return SourceFactory::create (*this, node, true);
2204 catch (failed_constructor& err) {
2205 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2206 return boost::shared_ptr<Source>();
2211 Session::save_template (string template_name, bool replace_existing)
2213 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2217 bool absolute_path = Glib::path_is_absolute (template_name);
2219 /* directory to put the template in */
2220 std::string template_dir_path;
2222 if (!absolute_path) {
2223 std::string user_template_dir(user_template_directory());
2225 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2226 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2227 user_template_dir, g_strerror (errno)) << endmsg;
2231 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2233 template_dir_path = template_name;
2236 if (!ARDOUR::Profile->get_trx()) {
2237 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2238 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2239 template_dir_path) << endmsg;
2243 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2244 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2245 template_dir_path, g_strerror (errno)) << endmsg;
2251 std::string template_file_path;
2253 if (ARDOUR::Profile->get_trx()) {
2254 template_file_path = template_name;
2256 if (absolute_path) {
2257 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2259 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2263 SessionSaveUnderway (); /* EMIT SIGNAL */
2268 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2269 tree.set_root (&get_template());
2272 if (!tree.write (template_file_path)) {
2273 error << _("template not saved") << endmsg;
2277 store_recent_templates (template_file_path);
2283 Session::refresh_disk_space ()
2285 #if __APPLE__ || __FreeBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2287 Glib::Threads::Mutex::Lock lm (space_lock);
2289 /* get freespace on every FS that is part of the session path */
2291 _total_free_4k_blocks = 0;
2292 _total_free_4k_blocks_uncertain = false;
2294 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2296 struct statfs statfsbuf;
2297 statfs (i->path.c_str(), &statfsbuf);
2299 double const scale = statfsbuf.f_bsize / 4096.0;
2301 /* See if this filesystem is read-only */
2302 struct statvfs statvfsbuf;
2303 statvfs (i->path.c_str(), &statvfsbuf);
2305 /* f_bavail can be 0 if it is undefined for whatever
2306 filesystem we are looking at; Samba shares mounted
2307 via GVFS are an example of this.
2309 if (statfsbuf.f_bavail == 0) {
2310 /* block count unknown */
2312 i->blocks_unknown = true;
2313 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2314 /* read-only filesystem */
2316 i->blocks_unknown = false;
2318 /* read/write filesystem with known space */
2319 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2320 i->blocks_unknown = false;
2323 _total_free_4k_blocks += i->blocks;
2324 if (i->blocks_unknown) {
2325 _total_free_4k_blocks_uncertain = true;
2328 #elif defined PLATFORM_WINDOWS
2329 vector<string> scanned_volumes;
2330 vector<string>::iterator j;
2331 vector<space_and_path>::iterator i;
2332 DWORD nSectorsPerCluster, nBytesPerSector,
2333 nFreeClusters, nTotalClusters;
2337 _total_free_4k_blocks = 0;
2339 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2340 strncpy (disk_drive, (*i).path.c_str(), 3);
2344 volume_found = false;
2345 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2347 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2348 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2349 i->blocks = (uint32_t)(nFreeBytes / 4096);
2351 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2352 if (0 == j->compare(disk_drive)) {
2353 volume_found = true;
2358 if (!volume_found) {
2359 scanned_volumes.push_back(disk_drive);
2360 _total_free_4k_blocks += i->blocks;
2365 if (0 == _total_free_4k_blocks) {
2366 strncpy (disk_drive, path().c_str(), 3);
2369 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2371 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2372 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2373 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2380 Session::get_best_session_directory_for_new_audio ()
2382 vector<space_and_path>::iterator i;
2383 string result = _session_dir->root_path();
2385 /* handle common case without system calls */
2387 if (session_dirs.size() == 1) {
2391 /* OK, here's the algorithm we're following here:
2393 We want to select which directory to use for
2394 the next file source to be created. Ideally,
2395 we'd like to use a round-robin process so as to
2396 get maximum performance benefits from splitting
2397 the files across multiple disks.
2399 However, in situations without much diskspace, an
2400 RR approach may end up filling up a filesystem
2401 with new files while others still have space.
2402 Its therefore important to pay some attention to
2403 the freespace in the filesystem holding each
2404 directory as well. However, if we did that by
2405 itself, we'd keep creating new files in the file
2406 system with the most space until it was as full
2407 as all others, thus negating any performance
2408 benefits of this RAID-1 like approach.
2410 So, we use a user-configurable space threshold. If
2411 there are at least 2 filesystems with more than this
2412 much space available, we use RR selection between them.
2413 If not, then we pick the filesystem with the most space.
2415 This gets a good balance between the two
2419 refresh_disk_space ();
2421 int free_enough = 0;
2423 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2424 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2429 if (free_enough >= 2) {
2430 /* use RR selection process, ensuring that the one
2434 i = last_rr_session_dir;
2437 if (++i == session_dirs.end()) {
2438 i = session_dirs.begin();
2441 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2442 SessionDirectory sdir(i->path);
2443 if (sdir.create ()) {
2445 last_rr_session_dir = i;
2450 } while (i != last_rr_session_dir);
2454 /* pick FS with the most freespace (and that
2455 seems to actually work ...)
2458 vector<space_and_path> sorted;
2459 space_and_path_ascending_cmp cmp;
2461 sorted = session_dirs;
2462 sort (sorted.begin(), sorted.end(), cmp);
2464 for (i = sorted.begin(); i != sorted.end(); ++i) {
2465 SessionDirectory sdir(i->path);
2466 if (sdir.create ()) {
2468 last_rr_session_dir = i;
2478 Session::automation_dir () const
2480 return Glib::build_filename (_path, automation_dir_name);
2484 Session::analysis_dir () const
2486 return Glib::build_filename (_path, analysis_dir_name);
2490 Session::plugins_dir () const
2492 return Glib::build_filename (_path, plugins_dir_name);
2496 Session::externals_dir () const
2498 return Glib::build_filename (_path, externals_dir_name);
2502 Session::load_bundles (XMLNode const & node)
2504 XMLNodeList nlist = node.children();
2505 XMLNodeConstIterator niter;
2509 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2510 if ((*niter)->name() == "InputBundle") {
2511 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2512 } else if ((*niter)->name() == "OutputBundle") {
2513 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2515 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2524 Session::load_route_groups (const XMLNode& node, int version)
2526 XMLNodeList nlist = node.children();
2527 XMLNodeConstIterator niter;
2531 if (version >= 3000) {
2533 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2534 if ((*niter)->name() == "RouteGroup") {
2535 RouteGroup* rg = new RouteGroup (*this, "");
2536 add_route_group (rg);
2537 rg->set_state (**niter, version);
2541 } else if (version < 3000) {
2543 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2544 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2545 RouteGroup* rg = new RouteGroup (*this, "");
2546 add_route_group (rg);
2547 rg->set_state (**niter, version);
2556 state_file_filter (const string &str, void* /*arg*/)
2558 return (str.length() > strlen(statefile_suffix) &&
2559 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2563 remove_end(string state)
2565 string statename(state);
2567 string::size_type start,end;
2568 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2569 statename = statename.substr (start+1);
2572 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2573 end = statename.length();
2576 return string(statename.substr (0, end));
2580 Session::possible_states (string path)
2582 vector<string> states;
2583 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2585 transform(states.begin(), states.end(), states.begin(), remove_end);
2587 sort (states.begin(), states.end());
2593 Session::possible_states () const
2595 return possible_states(_path);
2599 Session::add_route_group (RouteGroup* g)
2601 _route_groups.push_back (g);
2602 route_group_added (g); /* EMIT SIGNAL */
2604 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2605 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2606 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2612 Session::remove_route_group (RouteGroup& rg)
2614 list<RouteGroup*>::iterator i;
2616 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2617 _route_groups.erase (i);
2620 route_group_removed (); /* EMIT SIGNAL */
2624 /** Set a new order for our route groups, without adding or removing any.
2625 * @param groups Route group list in the new order.
2628 Session::reorder_route_groups (list<RouteGroup*> groups)
2630 _route_groups = groups;
2632 route_groups_reordered (); /* EMIT SIGNAL */
2638 Session::route_group_by_name (string name)
2640 list<RouteGroup *>::iterator i;
2642 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2643 if ((*i)->name() == name) {
2651 Session::all_route_group() const
2653 return *_all_route_group;
2657 Session::add_commands (vector<Command*> const & cmds)
2659 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2665 Session::add_command (Command* const cmd)
2667 assert (_current_trans);
2668 DEBUG_UNDO_HISTORY (
2669 string_compose ("Current Undo Transaction %1, adding command: %2",
2670 _current_trans->name (),
2672 _current_trans->add_command (cmd);
2675 PBD::StatefulDiffCommand*
2676 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2678 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2684 Session::begin_reversible_command (const string& name)
2686 begin_reversible_command (g_quark_from_string (name.c_str ()));
2689 /** Begin a reversible command using a GQuark to identify it.
2690 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2691 * but there must be as many begin...()s as there are commit...()s.
2694 Session::begin_reversible_command (GQuark q)
2696 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2697 to hold all the commands that are committed. This keeps the order of
2698 commands correct in the history.
2701 if (_current_trans == 0) {
2702 DEBUG_UNDO_HISTORY (string_compose (
2703 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2705 /* start a new transaction */
2706 assert (_current_trans_quarks.empty ());
2707 _current_trans = new UndoTransaction();
2708 _current_trans->set_name (g_quark_to_string (q));
2710 DEBUG_UNDO_HISTORY (
2711 string_compose ("Begin Reversible Command, current transaction: %1",
2712 _current_trans->name ()));
2715 _current_trans_quarks.push_front (q);
2719 Session::abort_reversible_command ()
2721 if (_current_trans != 0) {
2722 DEBUG_UNDO_HISTORY (
2723 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2724 _current_trans->clear();
2725 delete _current_trans;
2727 _current_trans_quarks.clear();
2732 Session::commit_reversible_command (Command *cmd)
2734 assert (_current_trans);
2735 assert (!_current_trans_quarks.empty ());
2740 DEBUG_UNDO_HISTORY (
2741 string_compose ("Current Undo Transaction %1, adding command: %2",
2742 _current_trans->name (),
2744 _current_trans->add_command (cmd);
2747 DEBUG_UNDO_HISTORY (
2748 string_compose ("Commit Reversible Command, current transaction: %1",
2749 _current_trans->name ()));
2751 _current_trans_quarks.pop_front ();
2753 if (!_current_trans_quarks.empty ()) {
2754 DEBUG_UNDO_HISTORY (
2755 string_compose ("Commit Reversible Command, transaction is not "
2756 "top-level, current transaction: %1",
2757 _current_trans->name ()));
2758 /* the transaction we're committing is not the top-level one */
2762 if (_current_trans->empty()) {
2763 /* no commands were added to the transaction, so just get rid of it */
2764 DEBUG_UNDO_HISTORY (
2765 string_compose ("Commit Reversible Command, No commands were "
2766 "added to current transaction: %1",
2767 _current_trans->name ()));
2768 delete _current_trans;
2773 gettimeofday (&now, 0);
2774 _current_trans->set_timestamp (now);
2776 _history.add (_current_trans);
2781 accept_all_audio_files (const string& path, void* /*arg*/)
2783 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2787 if (!AudioFileSource::safe_audio_file_extension (path)) {
2795 accept_all_midi_files (const string& path, void* /*arg*/)
2797 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2801 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2802 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2803 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2807 accept_all_state_files (const string& path, void* /*arg*/)
2809 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2813 std::string const statefile_ext (statefile_suffix);
2814 if (path.length() >= statefile_ext.length()) {
2815 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2822 Session::find_all_sources (string path, set<string>& result)
2827 if (!tree.read (path)) {
2831 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2836 XMLNodeConstIterator niter;
2838 nlist = node->children();
2842 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2844 XMLProperty const * prop;
2846 if ((prop = (*niter)->property (X_("type"))) == 0) {
2850 DataType type (prop->value());
2852 if ((prop = (*niter)->property (X_("name"))) == 0) {
2856 if (Glib::path_is_absolute (prop->value())) {
2857 /* external file, ignore */
2865 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2866 result.insert (found_path);
2874 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2876 vector<string> state_files;
2878 string this_snapshot_path;
2884 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2885 ripped = ripped.substr (0, ripped.length() - 1);
2888 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2890 if (state_files.empty()) {
2895 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2896 this_snapshot_path += statefile_suffix;
2898 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2900 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2902 if (exclude_this_snapshot && *i == this_snapshot_path) {
2903 cerr << "\texcluded\n";
2908 if (find_all_sources (*i, result) < 0) {
2916 struct RegionCounter {
2917 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2918 AudioSourceList::iterator iter;
2919 boost::shared_ptr<Region> region;
2922 RegionCounter() : count (0) {}
2926 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2928 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2929 return r.get_value_or (1);
2933 Session::cleanup_regions ()
2935 bool removed = false;
2936 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2938 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2940 uint32_t used = playlists->region_use_count (i->second);
2942 if (used == 0 && !i->second->automatic ()) {
2943 boost::weak_ptr<Region> w = i->second;
2946 RegionFactory::map_remove (w);
2953 // re-check to remove parent references of compound regions
2954 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2955 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2959 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2960 if (0 == playlists->region_use_count (i->second)) {
2961 boost::weak_ptr<Region> w = i->second;
2963 RegionFactory::map_remove (w);
2970 /* dump the history list */
2977 Session::can_cleanup_peakfiles () const
2979 if (deletion_in_progress()) {
2982 if (!_writable || (_state_of_the_state & CannotSave)) {
2983 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2986 if (record_status() == Recording) {
2987 error << _("Cannot cleanup peak-files while recording") << endmsg;
2994 Session::cleanup_peakfiles ()
2996 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3001 assert (can_cleanup_peakfiles ());
3002 assert (!peaks_cleanup_in_progres());
3004 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3006 int timeout = 5000; // 5 seconds
3007 while (!SourceFactory::files_with_peaks.empty()) {
3008 Glib::usleep (1000);
3009 if (--timeout < 0) {
3010 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3011 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3016 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3017 boost::shared_ptr<AudioSource> as;
3018 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3019 as->close_peakfile();
3023 PBD::clear_directory (session_directory().peak_path());
3025 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3027 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3028 boost::shared_ptr<AudioSource> as;
3029 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3030 SourceFactory::setup_peakfile(as, true);
3037 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3039 pl->deep_sources (*all_sources);
3043 Session::cleanup_sources (CleanupReport& rep)
3045 // FIXME: needs adaptation to midi
3047 vector<boost::shared_ptr<Source> > dead_sources;
3050 vector<string> candidates;
3051 vector<string> unused;
3052 set<string> sources_used_by_all_snapshots;
3059 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3061 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3063 /* this is mostly for windows which doesn't allow file
3064 * renaming if the file is in use. But we don't special
3065 * case it because we need to know if this causes
3066 * problems, and the easiest way to notice that is to
3067 * keep it in place for all platforms.
3070 request_stop (false);
3072 _butler->wait_until_finished ();
3074 /* consider deleting all unused playlists */
3076 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3081 /* sync the "all regions" property of each playlist with its current state
3084 playlists->sync_all_regions_with_regions ();
3086 /* find all un-used sources */
3091 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3093 SourceMap::iterator tmp;
3098 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3102 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3103 dead_sources.push_back (i->second);
3104 i->second->drop_references ();
3110 /* build a list of all the possible audio directories for the session */
3112 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3113 SessionDirectory sdir ((*i).path);
3114 asp += sdir.sound_path();
3116 audio_path += asp.to_string();
3119 /* build a list of all the possible midi directories for the session */
3121 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3122 SessionDirectory sdir ((*i).path);
3123 msp += sdir.midi_path();
3125 midi_path += msp.to_string();
3127 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3128 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3130 /* add sources from all other snapshots as "used", but don't use this
3131 snapshot because the state file on disk still references sources we
3132 may have already dropped.
3135 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3137 /* Although the region factory has a list of all regions ever created
3138 * for this session, we're only interested in regions actually in
3139 * playlists right now. So merge all playlist regions lists together.
3141 * This will include the playlists used within compound regions.
3144 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3146 /* add our current source list
3149 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3150 boost::shared_ptr<FileSource> fs;
3151 SourceMap::iterator tmp = i;
3154 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3160 /* this is mostly for windows which doesn't allow file
3161 * renaming if the file is in use. But we do not special
3162 * case it because we need to know if this causes
3163 * problems, and the easiest way to notice that is to
3164 * keep it in place for all platforms.
3169 if (!fs->is_stub()) {
3171 /* Note that we're checking a list of all
3172 * sources across all snapshots with the list
3173 * of sources used by this snapshot.
3176 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3177 /* this source is in use by this snapshot */
3178 sources_used_by_all_snapshots.insert (fs->path());
3179 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3181 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3182 /* this source is NOT in use by this snapshot
3185 /* remove all related regions from RegionFactory master list
3188 RegionFactory::remove_regions_using_source (i->second);
3190 /* remove from our current source list
3191 * also. We may not remove it from
3192 * disk, because it may be used by
3193 * other snapshots, but it isn't used inside this
3194 * snapshot anymore, so we don't need a
3205 /* now check each candidate source to see if it exists in the list of
3206 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3209 cerr << "Candidates: " << candidates.size() << endl;
3210 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3212 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3217 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3219 tmppath1 = canonical_path (spath);
3220 tmppath2 = canonical_path ((*i));
3222 cerr << "\t => " << tmppath2 << endl;
3224 if (tmppath1 == tmppath2) {
3231 unused.push_back (spath);
3235 cerr << "Actually unused: " << unused.size() << endl;
3237 if (unused.empty()) {
3243 /* now try to move all unused files into the "dead" directory(ies) */
3245 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3250 /* don't move the file across filesystems, just
3251 stick it in the `dead_dir_name' directory
3252 on whichever filesystem it was already on.
3255 if ((*x).find ("/sounds/") != string::npos) {
3257 /* old school, go up 1 level */
3259 newpath = Glib::path_get_dirname (*x); // "sounds"
3260 newpath = Glib::path_get_dirname (newpath); // "session-name"
3264 /* new school, go up 4 levels */
3266 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3267 newpath = Glib::path_get_dirname (newpath); // "session-name"
3268 newpath = Glib::path_get_dirname (newpath); // "interchange"
3269 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3272 newpath = Glib::build_filename (newpath, dead_dir_name);
3274 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3275 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3279 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3281 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3283 /* the new path already exists, try versioning */
3285 char buf[PATH_MAX+1];
3289 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3292 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3293 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3297 if (version == 999) {
3298 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3302 newpath = newpath_v;
3307 if (0 == g_stat ((*x).c_str(), &statbuf)) {
3309 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3310 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x), newpath, strerror (errno)) << endmsg;
3314 /* see if there an easy to find peakfile for this file, and remove it.
3317 string base = Glib::path_get_basename (*x);
3318 base += "%A"; /* this is what we add for the channel suffix of all native files,
3319 or for the first channel of embedded files. it will miss
3320 some peakfiles for other channels
3322 string peakpath = construct_peak_filepath (base);
3324 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3325 if (::g_unlink (peakpath.c_str()) != 0) {
3326 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3327 peakpath, _path, strerror (errno))
3329 /* try to back out */
3330 ::rename (newpath.c_str(), _path.c_str());
3335 rep.paths.push_back (*x);
3336 rep.space += statbuf.st_size;
3340 /* dump the history list */
3344 /* save state so we don't end up a session file
3345 referring to non-existent sources.
3352 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3358 Session::cleanup_trash_sources (CleanupReport& rep)
3360 // FIXME: needs adaptation for MIDI
3362 vector<space_and_path>::iterator i;
3368 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3370 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3372 clear_directory (dead_dir, &rep.space, &rep.paths);
3379 Session::set_dirty ()
3381 /* never mark session dirty during loading */
3383 if (_state_of_the_state & Loading) {
3387 bool was_dirty = dirty();
3389 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3393 DirtyChanged(); /* EMIT SIGNAL */
3399 Session::set_clean ()
3401 bool was_dirty = dirty();
3403 _state_of_the_state = Clean;
3407 DirtyChanged(); /* EMIT SIGNAL */
3412 Session::set_deletion_in_progress ()
3414 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3418 Session::clear_deletion_in_progress ()
3420 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3424 Session::add_controllable (boost::shared_ptr<Controllable> c)
3426 /* this adds a controllable to the list managed by the Session.
3427 this is a subset of those managed by the Controllable class
3428 itself, and represents the only ones whose state will be saved
3429 as part of the session.
3432 Glib::Threads::Mutex::Lock lm (controllables_lock);
3433 controllables.insert (c);
3436 struct null_deleter { void operator()(void const *) const {} };
3439 Session::remove_controllable (Controllable* c)
3441 if (_state_of_the_state & Deletion) {
3445 Glib::Threads::Mutex::Lock lm (controllables_lock);
3447 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3449 if (x != controllables.end()) {
3450 controllables.erase (x);
3454 boost::shared_ptr<Controllable>
3455 Session::controllable_by_id (const PBD::ID& id)
3457 Glib::Threads::Mutex::Lock lm (controllables_lock);
3459 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3460 if ((*i)->id() == id) {
3465 return boost::shared_ptr<Controllable>();
3468 boost::shared_ptr<Controllable>
3469 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3471 boost::shared_ptr<Controllable> c;
3472 boost::shared_ptr<Stripable> s;
3473 boost::shared_ptr<Route> r;
3475 switch (desc.top_level_type()) {
3476 case ControllableDescriptor::NamedRoute:
3478 std::string str = desc.top_level_name();
3480 if (str == "Master" || str == "master") {
3482 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3484 } else if (str == "auditioner") {
3487 s = route_by_name (desc.top_level_name());
3493 case ControllableDescriptor::PresentationOrderRoute:
3494 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3497 case ControllableDescriptor::PresentationOrderTrack:
3498 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3501 case ControllableDescriptor::PresentationOrderBus:
3502 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3505 case ControllableDescriptor::PresentationOrderVCA:
3506 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3509 case ControllableDescriptor::SelectionCount:
3510 s = route_by_selected_count (desc.selection_id());
3518 r = boost::dynamic_pointer_cast<Route> (s);
3520 switch (desc.subtype()) {
3521 case ControllableDescriptor::Gain:
3522 c = s->gain_control ();
3525 case ControllableDescriptor::Trim:
3526 c = s->trim_control ();
3529 case ControllableDescriptor::Solo:
3530 c = s->solo_control();
3533 case ControllableDescriptor::Mute:
3534 c = s->mute_control();
3537 case ControllableDescriptor::Recenable:
3538 c = s->rec_enable_control ();
3541 case ControllableDescriptor::PanDirection:
3542 c = s->pan_azimuth_control();
3545 case ControllableDescriptor::PanWidth:
3546 c = s->pan_width_control();
3549 case ControllableDescriptor::PanElevation:
3550 c = s->pan_elevation_control();
3553 case ControllableDescriptor::Balance:
3554 /* XXX simple pan control */
3557 case ControllableDescriptor::PluginParameter:
3559 uint32_t plugin = desc.target (0);
3560 uint32_t parameter_index = desc.target (1);
3562 /* revert to zero based counting */
3568 if (parameter_index > 0) {
3576 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3579 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3580 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3585 case ControllableDescriptor::SendGain: {
3586 uint32_t send = desc.target (0);
3593 c = r->send_level_controllable (send);
3598 /* relax and return a null pointer */
3606 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3609 Stateful::add_instant_xml (node, _path);
3612 if (write_to_config) {
3613 Config->add_instant_xml (node);
3618 Session::instant_xml (const string& node_name)
3620 return Stateful::instant_xml (node_name, _path);
3624 Session::save_history (string snapshot_name)
3632 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3633 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3637 if (snapshot_name.empty()) {
3638 snapshot_name = _current_snapshot_name;
3641 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3642 const string backup_filename = history_filename + backup_suffix;
3643 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3644 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3646 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3647 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3648 error << _("could not backup old history file, current history not saved") << endmsg;
3653 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3655 if (!tree.write (xml_path))
3657 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3659 if (g_remove (xml_path.c_str()) != 0) {
3660 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3661 xml_path, g_strerror (errno)) << endmsg;
3663 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3664 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3665 backup_path, g_strerror (errno)) << endmsg;
3675 Session::restore_history (string snapshot_name)
3679 if (snapshot_name.empty()) {
3680 snapshot_name = _current_snapshot_name;
3683 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3684 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3686 info << "Loading history from " << xml_path << endmsg;
3688 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3689 info << string_compose (_("%1: no history file \"%2\" for this session."),
3690 _name, xml_path) << endmsg;
3694 if (!tree.read (xml_path)) {
3695 error << string_compose (_("Could not understand session history file \"%1\""),
3696 xml_path) << endmsg;
3703 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3706 UndoTransaction* ut = new UndoTransaction ();
3709 ut->set_name(t->property("name")->value());
3710 stringstream ss(t->property("tv-sec")->value());
3712 ss.str(t->property("tv-usec")->value());
3714 ut->set_timestamp(tv);
3716 for (XMLNodeConstIterator child_it = t->children().begin();
3717 child_it != t->children().end(); child_it++)
3719 XMLNode *n = *child_it;
3722 if (n->name() == "MementoCommand" ||
3723 n->name() == "MementoUndoCommand" ||
3724 n->name() == "MementoRedoCommand") {
3726 if ((c = memento_command_factory(n))) {
3730 } else if (n->name() == "NoteDiffCommand") {
3731 PBD::ID id (n->property("midi-source")->value());
3732 boost::shared_ptr<MidiSource> midi_source =
3733 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3735 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3737 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3740 } else if (n->name() == "SysExDiffCommand") {
3742 PBD::ID id (n->property("midi-source")->value());
3743 boost::shared_ptr<MidiSource> midi_source =
3744 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3746 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3748 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3751 } else if (n->name() == "PatchChangeDiffCommand") {
3753 PBD::ID id (n->property("midi-source")->value());
3754 boost::shared_ptr<MidiSource> midi_source =
3755 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3757 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3759 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3762 } else if (n->name() == "StatefulDiffCommand") {
3763 if ((c = stateful_diff_command_factory (n))) {
3764 ut->add_command (c);
3767 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3778 Session::config_changed (std::string p, bool ours)
3784 if (p == "seamless-loop") {
3786 } else if (p == "rf-speed") {
3788 } else if (p == "auto-loop") {
3790 } else if (p == "auto-input") {
3792 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3793 /* auto-input only makes a difference if we're rolling */
3794 set_track_monitor_input_status (!config.get_auto_input());
3797 } else if (p == "punch-in") {
3801 if ((location = _locations->auto_punch_location()) != 0) {
3803 if (config.get_punch_in ()) {
3804 replace_event (SessionEvent::PunchIn, location->start());
3806 remove_event (location->start(), SessionEvent::PunchIn);
3810 } else if (p == "punch-out") {
3814 if ((location = _locations->auto_punch_location()) != 0) {
3816 if (config.get_punch_out()) {
3817 replace_event (SessionEvent::PunchOut, location->end());
3819 clear_events (SessionEvent::PunchOut);
3823 } else if (p == "edit-mode") {
3825 Glib::Threads::Mutex::Lock lm (playlists->lock);
3827 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3828 (*i)->set_edit_mode (Config->get_edit_mode ());
3831 } else if (p == "use-video-sync") {
3833 waiting_for_sync_offset = config.get_use_video_sync();
3835 } else if (p == "mmc-control") {
3837 //poke_midi_thread ();
3839 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3841 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3843 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3845 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3847 } else if (p == "midi-control") {
3849 //poke_midi_thread ();
3851 } else if (p == "raid-path") {
3853 setup_raid_path (config.get_raid_path());
3855 } else if (p == "timecode-format") {
3859 } else if (p == "video-pullup") {
3863 } else if (p == "seamless-loop") {
3865 if (play_loop && transport_rolling()) {
3866 // to reset diskstreams etc
3867 request_play_loop (true);
3870 } else if (p == "rf-speed") {
3872 cumulative_rf_motion = 0;
3875 } else if (p == "click-sound") {
3877 setup_click_sounds (1);
3879 } else if (p == "click-emphasis-sound") {
3881 setup_click_sounds (-1);
3883 } else if (p == "clicking") {
3885 if (Config->get_clicking()) {
3886 if (_click_io && click_data) { // don't require emphasis data
3893 } else if (p == "click-gain") {
3896 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3899 } else if (p == "send-mtc") {
3901 if (Config->get_send_mtc ()) {
3902 /* mark us ready to send */
3903 next_quarter_frame_to_send = 0;
3906 } else if (p == "send-mmc") {
3908 _mmc->enable_send (Config->get_send_mmc ());
3910 } else if (p == "midi-feedback") {
3912 session_midi_feedback = Config->get_midi_feedback();
3914 } else if (p == "jack-time-master") {
3916 engine().reset_timebase ();
3918 } else if (p == "native-file-header-format") {
3920 if (!first_file_header_format_reset) {
3921 reset_native_file_format ();
3924 first_file_header_format_reset = false;
3926 } else if (p == "native-file-data-format") {
3928 if (!first_file_data_format_reset) {
3929 reset_native_file_format ();
3932 first_file_data_format_reset = false;
3934 } else if (p == "external-sync") {
3935 if (!config.get_external_sync()) {
3936 drop_sync_source ();
3938 switch_to_sync_source (Config->get_sync_source());
3940 } else if (p == "denormal-model") {
3942 } else if (p == "history-depth") {
3943 set_history_depth (Config->get_history_depth());
3944 } else if (p == "remote-model") {
3945 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3948 } else if (p == "initial-program-change") {
3950 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3953 buf[0] = MIDI::program; // channel zero by default
3954 buf[1] = (Config->get_initial_program_change() & 0x7f);
3956 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3958 } else if (p == "solo-mute-override") {
3959 // catch_up_on_solo_mute_override ();
3960 } else if (p == "listen-position" || p == "pfl-position") {
3961 listen_position_changed ();
3962 } else if (p == "solo-control-is-listen-control") {
3963 solo_control_mode_changed ();
3964 } else if (p == "solo-mute-gain") {
3965 _solo_cut_control->Changed (true, Controllable::NoGroup);
3966 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3967 last_timecode_valid = false;
3968 } else if (p == "playback-buffer-seconds") {
3969 AudioSource::allocate_working_buffers (frame_rate());
3970 } else if (p == "ltc-source-port") {
3971 reconnect_ltc_input ();
3972 } else if (p == "ltc-sink-port") {
3973 reconnect_ltc_output ();
3974 } else if (p == "timecode-generator-offset") {
3975 ltc_tx_parse_offset();
3976 } else if (p == "auto-return-target-list") {
3977 follow_playhead_priority ();
3984 Session::set_history_depth (uint32_t d)
3986 _history.set_depth (d);
3990 Session::load_diskstreams_2X (XMLNode const & node, int)
3993 XMLNodeConstIterator citer;
3995 clist = node.children();
3997 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4000 /* diskstreams added automatically by DiskstreamCreated handler */
4001 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4002 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4003 _diskstreams_2X.push_back (dsp);
4005 error << _("Session: unknown diskstream type in XML") << endmsg;
4009 catch (failed_constructor& err) {
4010 error << _("Session: could not load diskstream via XML state") << endmsg;
4018 /** Connect things to the MMC object */
4020 Session::setup_midi_machine_control ()
4022 _mmc = new MIDI::MachineControl;
4024 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4025 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4027 if (!async_out || !async_out) {
4031 /* XXXX argh, passing raw pointers back into libmidi++ */
4033 MIDI::Port* mmc_in = async_in.get();
4034 MIDI::Port* mmc_out = async_out.get();
4036 _mmc->set_ports (mmc_in, mmc_out);
4038 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4039 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4040 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4041 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4042 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4043 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4044 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4045 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4046 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4047 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4048 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4049 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4050 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4052 /* also handle MIDI SPP because its so common */
4054 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4055 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4056 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4059 boost::shared_ptr<Controllable>
4060 Session::solo_cut_control() const
4062 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4063 controls in Ardour that currently get presented to the user in the GUI that require
4064 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4066 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4067 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4071 return _solo_cut_control;
4075 Session::save_snapshot_name (const std::string & n)
4077 /* assure Stateful::_instant_xml is loaded
4078 * add_instant_xml() only adds to existing data and defaults
4079 * to use an empty Tree otherwise
4081 instant_xml ("LastUsedSnapshot");
4083 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4084 last_used_snapshot->add_property ("name", string(n));
4085 add_instant_xml (*last_used_snapshot, false);
4089 Session::set_snapshot_name (const std::string & n)
4091 _current_snapshot_name = n;
4092 save_snapshot_name (n);
4096 Session::rename (const std::string& new_name)
4098 string legal_name = legalize_for_path (new_name);
4104 string const old_sources_root = _session_dir->sources_root();
4106 if (!_writable || (_state_of_the_state & CannotSave)) {
4107 error << _("Cannot rename read-only session.") << endmsg;
4108 return 0; // don't show "messed up" warning
4110 if (record_status() == Recording) {
4111 error << _("Cannot rename session while recording") << endmsg;
4112 return 0; // don't show "messed up" warning
4115 StateProtector stp (this);
4120 * interchange subdirectory
4124 * Backup files are left unchanged and not renamed.
4127 /* Windows requires that we close all files before attempting the
4128 * rename. This works on other platforms, but isn't necessary there.
4129 * Leave it in place for all platforms though, since it may help
4130 * catch issues that could arise if the way Source files work ever
4131 * change (since most developers are not using Windows).
4134 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4135 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4141 /* pass one: not 100% safe check that the new directory names don't
4145 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4149 /* this is a stupid hack because Glib::path_get_dirname() is
4150 * lexical-only, and so passing it /a/b/c/ gives a different
4151 * result than passing it /a/b/c ...
4154 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4155 oldstr = oldstr.substr (0, oldstr.length() - 1);
4158 string base = Glib::path_get_dirname (oldstr);
4160 newstr = Glib::build_filename (base, legal_name);
4162 cerr << "Looking for " << newstr << endl;
4164 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4165 cerr << " exists\n";
4174 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4180 /* this is a stupid hack because Glib::path_get_dirname() is
4181 * lexical-only, and so passing it /a/b/c/ gives a different
4182 * result than passing it /a/b/c ...
4185 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4186 oldstr = oldstr.substr (0, oldstr.length() - 1);
4189 string base = Glib::path_get_dirname (oldstr);
4190 newstr = Glib::build_filename (base, legal_name);
4192 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4194 cerr << "Rename " << oldstr << " => " << newstr << endl;
4195 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4196 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4197 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4201 /* Reset path in "session dirs" */
4206 /* reset primary SessionDirectory object */
4209 (*_session_dir) = newstr;
4214 /* now rename directory below session_dir/interchange */
4216 string old_interchange_dir;
4217 string new_interchange_dir;
4219 /* use newstr here because we renamed the path
4220 * (folder/directory) that used to be oldstr to newstr above
4223 v.push_back (newstr);
4224 v.push_back (interchange_dir_name);
4225 v.push_back (Glib::path_get_basename (oldstr));
4227 old_interchange_dir = Glib::build_filename (v);
4230 v.push_back (newstr);
4231 v.push_back (interchange_dir_name);
4232 v.push_back (legal_name);
4234 new_interchange_dir = Glib::build_filename (v);
4236 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4238 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4239 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4240 old_interchange_dir, new_interchange_dir,
4243 error << string_compose (_("renaming %s as %2 failed (%3)"),
4244 old_interchange_dir, new_interchange_dir,
4253 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4254 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4256 cerr << "Rename " << oldstr << " => " << newstr << endl;
4258 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4259 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4260 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4266 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4268 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4269 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4271 cerr << "Rename " << oldstr << " => " << newstr << endl;
4273 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4274 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4275 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4280 /* remove old name from recent sessions */
4281 remove_recent_sessions (_path);
4284 /* update file source paths */
4286 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4287 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4289 string p = fs->path ();
4290 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4292 SourceFactory::setup_peakfile(i->second, true);
4296 set_snapshot_name (new_name);
4301 /* save state again to get everything just right */
4303 save_state (_current_snapshot_name);
4305 /* add to recent sessions */
4307 store_recent_sessions (new_name, _path);
4313 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4315 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4319 if (!tree.read (xmlpath)) {
4327 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4330 bool found_sr = false;
4331 bool found_data_format = false;
4333 if (get_session_info_from_path (tree, xmlpath)) {
4339 XMLProperty const * prop;
4340 XMLNode const * root (tree.root());
4342 if ((prop = root->property (X_("sample-rate"))) != 0) {
4343 sample_rate = atoi (prop->value());
4347 const XMLNodeList& children (root->children());
4348 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4349 const XMLNode* child = *c;
4350 if (child->name() == "Config") {
4351 const XMLNodeList& options (child->children());
4352 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4353 XMLNode const * option = *oc;
4354 XMLProperty const * name = option->property("name");
4360 if (name->value() == "native-file-data-format") {
4361 XMLProperty const * value = option->property ("value");
4363 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4365 found_data_format = true;
4371 if (found_data_format) {
4376 return !(found_sr && found_data_format); // zero if they are both found
4380 Session::get_snapshot_from_instant (const std::string& session_dir)
4382 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4384 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4389 if (!tree.read (instant_xml_path)) {
4393 XMLProperty const * prop;
4394 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4395 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4396 return prop->value();
4402 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4403 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4406 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4410 SourcePathMap source_path_map;
4412 boost::shared_ptr<AudioFileSource> afs;
4417 Glib::Threads::Mutex::Lock lm (source_lock);
4419 cerr << " total sources = " << sources.size();
4421 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4422 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4428 if (fs->within_session()) {
4432 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4433 source_path_map[fs->path()].push_back (fs);
4435 SeveralFileSources v;
4437 source_path_map.insert (make_pair (fs->path(), v));
4443 cerr << " fsources = " << total << endl;
4445 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4447 /* tell caller where we are */
4449 string old_path = i->first;
4451 callback (n, total, old_path);
4453 cerr << old_path << endl;
4457 switch (i->second.front()->type()) {
4458 case DataType::AUDIO:
4459 new_path = new_audio_source_path_for_embedded (old_path);
4462 case DataType::MIDI:
4463 /* XXX not implemented yet */
4467 if (new_path.empty()) {
4471 cerr << "Move " << old_path << " => " << new_path << endl;
4473 if (!copy_file (old_path, new_path)) {
4474 cerr << "failed !\n";
4478 /* make sure we stop looking in the external
4479 dir/folder. Remember, this is an all-or-nothing
4480 operations, it doesn't merge just some files.
4482 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4484 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4485 (*f)->set_path (new_path);
4490 save_state ("", false, false);
4496 bool accept_all_files (string const &, void *)
4502 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4504 /* 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.
4509 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4511 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4513 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4515 v.push_back (new_session_folder); /* full path */
4516 v.push_back (interchange_dir_name);
4517 v.push_back (new_session_path); /* just one directory/folder */
4518 v.push_back (typedir);
4519 v.push_back (Glib::path_get_basename (old_path));
4521 return Glib::build_filename (v);
4525 Session::save_as (SaveAs& saveas)
4527 vector<string> files;
4528 string current_folder = Glib::path_get_dirname (_path);
4529 string new_folder = legalize_for_path (saveas.new_name);
4530 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4531 int64_t total_bytes = 0;
4535 int32_t internal_file_cnt = 0;
4537 vector<string> do_not_copy_extensions;
4538 do_not_copy_extensions.push_back (statefile_suffix);
4539 do_not_copy_extensions.push_back (pending_suffix);
4540 do_not_copy_extensions.push_back (backup_suffix);
4541 do_not_copy_extensions.push_back (temp_suffix);
4542 do_not_copy_extensions.push_back (history_suffix);
4544 /* get total size */
4546 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4548 /* need to clear this because
4549 * find_files_matching_filter() is cumulative
4554 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4556 all += files.size();
4558 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4560 g_stat ((*i).c_str(), &gsb);
4561 total_bytes += gsb.st_size;
4565 /* save old values so we can switch back if we are not switching to the new session */
4567 string old_path = _path;
4568 string old_name = _name;
4569 string old_snapshot = _current_snapshot_name;
4570 string old_sd = _session_dir->root_path();
4571 vector<string> old_search_path[DataType::num_types];
4572 string old_config_search_path[DataType::num_types];
4574 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4575 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4576 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4577 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4579 /* switch session directory */
4581 (*_session_dir) = to_dir;
4583 /* create new tree */
4585 if (!_session_dir->create()) {
4586 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4591 /* copy all relevant files. Find each location in session_dirs,
4592 * and copy files from there to target.
4595 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4597 /* need to clear this because
4598 * find_files_matching_filter() is cumulative
4603 const size_t prefix_len = (*sd).path.size();
4605 /* Work just on the files within this session dir */
4607 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4609 /* add dir separator to protect against collisions with
4610 * track names (e.g. track named "audiofiles" or
4614 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4615 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4616 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4618 /* copy all the files. Handling is different for media files
4619 than others because of the *silly* subtree we have below the interchange
4620 folder. That really was a bad idea, but I'm not fixing it as part of
4621 implementing ::save_as().
4624 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4626 std::string from = *i;
4629 string filename = Glib::path_get_basename (from);
4630 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4631 if (filename == ".DS_STORE") {
4636 if (from.find (audiofile_dir_string) != string::npos) {
4638 /* audio file: only copy if asked */
4640 if (saveas.include_media && saveas.copy_media) {
4642 string to = make_new_media_path (*i, to_dir, new_folder);
4644 info << "media file copying from " << from << " to " << to << endmsg;
4646 if (!copy_file (from, to)) {
4647 throw Glib::FileError (Glib::FileError::IO_ERROR,
4648 string_compose(_("\ncopying \"%1\" failed !"), from));
4652 /* we found media files inside the session folder */
4654 internal_file_cnt++;
4656 } else if (from.find (midifile_dir_string) != string::npos) {
4658 /* midi file: always copy unless
4659 * creating an empty new session
4662 if (saveas.include_media) {
4664 string to = make_new_media_path (*i, to_dir, new_folder);
4666 info << "media file copying from " << from << " to " << to << endmsg;
4668 if (!copy_file (from, to)) {
4669 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4673 /* we found media files inside the session folder */
4675 internal_file_cnt++;
4677 } else if (from.find (analysis_dir_string) != string::npos) {
4679 /* make sure analysis dir exists in
4680 * new session folder, but we're not
4681 * copying analysis files here, see
4685 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4690 /* normal non-media file. Don't copy state, history, etc.
4693 bool do_copy = true;
4695 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4696 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4697 /* end of filename matches extension, do not copy file */
4703 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4704 /* don't copy peakfiles if
4705 * we're not copying media
4711 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4713 info << "attempting to make directory/folder " << to << endmsg;
4715 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4716 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4719 info << "attempting to copy " << from << " to " << to << endmsg;
4721 if (!copy_file (from, to)) {
4722 throw Glib::FileError (Glib::FileError::IO_ERROR,
4723 string_compose(_("\ncopying \"%1\" failed !"), from));
4728 /* measure file size even if we're not going to copy so that our Progress
4729 signals are correct, since we included these do-not-copy files
4730 in the computation of the total size and file count.
4734 g_stat (from.c_str(), &gsb);
4735 copied += gsb.st_size;
4738 double fraction = (double) copied / total_bytes;
4740 bool keep_going = true;
4742 if (saveas.copy_media) {
4744 /* no need or expectation of this if
4745 * media is not being copied, because
4746 * it will be fast(ish).
4749 /* tell someone "X percent, file M of N"; M is one-based */
4751 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4759 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4765 /* copy optional folders, if any */
4767 string old = plugins_dir ();
4768 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4769 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4770 copy_files (old, newdir);
4773 old = externals_dir ();
4774 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4775 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4776 copy_files (old, newdir);
4779 old = automation_dir ();
4780 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4781 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4782 copy_files (old, newdir);
4785 if (saveas.include_media) {
4787 if (saveas.copy_media) {
4788 #ifndef PLATFORM_WINDOWS
4789 /* There are problems with analysis files on
4790 * Windows, because they used a colon in their
4791 * names as late as 4.0. Colons are not legal
4792 * under Windows even if NTFS allows them.
4794 * This is a tricky problem to solve so for
4795 * just don't copy these files. They will be
4796 * regenerated as-needed anyway, subject to the
4797 * existing issue that the filenames will be
4798 * rejected by Windows, which is a separate
4799 * problem (though related).
4802 /* only needed if we are copying media, since the
4803 * analysis data refers to media data
4806 old = analysis_dir ();
4807 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4808 string newdir = Glib::build_filename (to_dir, "analysis");
4809 copy_files (old, newdir);
4811 #endif /* PLATFORM_WINDOWS */
4817 set_snapshot_name (saveas.new_name);
4818 _name = saveas.new_name;
4820 if (saveas.include_media && !saveas.copy_media) {
4822 /* reset search paths of the new session (which we're pretending to be right now) to
4823 include the original session search path, so we can still find all audio.
4826 if (internal_file_cnt) {
4827 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4828 ensure_search_path_includes (*s, DataType::AUDIO);
4829 cerr << "be sure to include " << *s << " for audio" << endl;
4832 /* we do not do this for MIDI because we copy
4833 all MIDI files if saveas.include_media is
4839 bool was_dirty = dirty ();
4841 save_state ("", false, false, !saveas.include_media);
4842 save_default_options ();
4844 if (saveas.copy_media && saveas.copy_external) {
4845 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4846 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4850 saveas.final_session_folder_name = _path;
4852 store_recent_sessions (_name, _path);
4854 if (!saveas.switch_to) {
4856 /* switch back to the way things were */
4860 set_snapshot_name (old_snapshot);
4862 (*_session_dir) = old_sd;
4868 if (internal_file_cnt) {
4869 /* reset these to their original values */
4870 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4871 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4876 /* prune session dirs, and update disk space statistics
4881 session_dirs.clear ();
4882 session_dirs.push_back (sp);
4883 refresh_disk_space ();
4885 /* ensure that all existing tracks reset their current capture source paths
4887 reset_write_sources (true, true);
4889 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4890 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4893 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4894 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4900 if (fs->within_session()) {
4901 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4902 fs->set_path (newpath);
4907 } catch (Glib::FileError& e) {
4909 saveas.failure_message = e.what();
4911 /* recursively remove all the directories */
4913 remove_directory (to_dir);
4921 saveas.failure_message = _("unknown reason");
4923 /* recursively remove all the directories */
4925 remove_directory (to_dir);
4936 Session::undo (uint32_t n)
4938 if (actively_recording()) {
4946 Session::redo (uint32_t n)
4948 if (actively_recording()) {