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"
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 save_snapshot_name (snapshot_name);
1011 Session::load_options (const XMLNode& node)
1014 config.set_variables (node);
1019 Session::save_default_options ()
1021 return config.save_state();
1025 Session::get_state()
1031 Session::get_template()
1033 /* if we don't disable rec-enable, diskstreams
1034 will believe they need to store their capture
1035 sources in their state node.
1038 disable_record (false);
1040 return state(false);
1044 Session::state (bool full_state)
1047 XMLNode* node = new XMLNode("Session");
1051 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1052 node->add_property("version", buf);
1054 child = node->add_child ("ProgramVersion");
1055 child->add_property("created-with", created_with);
1057 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1058 child->add_property("modified-with", modified_with);
1060 /* store configuration settings */
1064 node->add_property ("name", _name);
1065 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1066 node->add_property ("sample-rate", buf);
1068 if (session_dirs.size() > 1) {
1072 vector<space_and_path>::iterator i = session_dirs.begin();
1073 vector<space_and_path>::iterator next;
1075 ++i; /* skip the first one */
1079 while (i != session_dirs.end()) {
1083 if (next != session_dirs.end()) {
1084 p += G_SEARCHPATH_SEPARATOR;
1093 child = node->add_child ("Path");
1094 child->add_content (p);
1098 /* save the ID counter */
1100 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1101 node->add_property ("id-counter", buf);
1103 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1104 node->add_property ("name-counter", buf);
1106 /* save the event ID counter */
1108 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1109 node->add_property ("event-counter", buf);
1111 /* save the VCA counter */
1113 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1114 node->add_property ("vca-counter", buf);
1116 /* various options */
1118 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1119 if (!midi_port_nodes.empty()) {
1120 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1121 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1122 midi_port_stuff->add_child_nocopy (**n);
1124 node->add_child_nocopy (*midi_port_stuff);
1127 node->add_child_nocopy (config.get_variables ());
1129 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1131 child = node->add_child ("Sources");
1134 Glib::Threads::Mutex::Lock sl (source_lock);
1136 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1138 /* Don't save information about non-file Sources, or
1139 * about non-destructive file sources that are empty
1140 * and unused by any regions.
1143 boost::shared_ptr<FileSource> fs;
1145 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1147 if (!fs->destructive()) {
1148 if (fs->empty() && !fs->used()) {
1153 child->add_child_nocopy (siter->second->get_state());
1158 child = node->add_child ("Regions");
1161 Glib::Threads::Mutex::Lock rl (region_lock);
1162 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1163 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1164 boost::shared_ptr<Region> r = i->second;
1165 /* only store regions not attached to playlists */
1166 if (r->playlist() == 0) {
1167 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1168 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1170 child->add_child_nocopy (r->get_state ());
1175 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1177 if (!cassocs.empty()) {
1178 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1180 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1182 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1183 i->first->id().print (buf, sizeof (buf));
1184 can->add_property (X_("copy"), buf);
1185 i->second->id().print (buf, sizeof (buf));
1186 can->add_property (X_("original"), buf);
1187 ca->add_child_nocopy (*can);
1197 node->add_child_nocopy (_locations->get_state());
1200 Locations loc (*this);
1201 // for a template, just create a new Locations, populate it
1202 // with the default start and end, and get the state for that.
1203 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1204 range->set (max_framepos, 0);
1206 XMLNode& locations_state = loc.get_state();
1208 if (ARDOUR::Profile->get_trx() && _locations) {
1209 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1210 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1211 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1212 locations_state.add_child_nocopy ((*i)->get_state ());
1216 node->add_child_nocopy (locations_state);
1219 child = node->add_child ("Bundles");
1221 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1222 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1223 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1225 child->add_child_nocopy (b->get_state());
1230 node->add_child_nocopy (_vca_manager->get_state());
1232 child = node->add_child ("Routes");
1234 boost::shared_ptr<RouteList> r = routes.reader ();
1236 RoutePublicOrderSorter cmp;
1237 RouteList public_order (*r);
1238 public_order.sort (cmp);
1240 /* the sort should have put the monitor out first */
1243 assert (_monitor_out == public_order.front());
1246 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1247 if (!(*i)->is_auditioner()) {
1249 child->add_child_nocopy ((*i)->get_state());
1251 child->add_child_nocopy ((*i)->get_template());
1257 playlists->add_state (node, full_state);
1259 child = node->add_child ("RouteGroups");
1260 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1261 child->add_child_nocopy ((*i)->get_state());
1265 XMLNode* gain_child = node->add_child ("Click");
1266 gain_child->add_child_nocopy (_click_io->state (full_state));
1267 gain_child->add_child_nocopy (_click_gain->state (full_state));
1271 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1272 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1276 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1277 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1280 node->add_child_nocopy (_speakers->get_state());
1281 node->add_child_nocopy (_tempo_map->get_state());
1282 node->add_child_nocopy (get_control_protocol_state());
1285 node->add_child_copy (*_extra_xml);
1289 Glib::Threads::Mutex::Lock lm (lua_lock);
1292 luabridge::LuaRef savedstate ((*_lua_save)());
1293 saved = savedstate.cast<std::string>();
1295 lua.collect_garbage ();
1298 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1299 std::string b64s (b64);
1302 XMLNode* script_node = new XMLNode (X_("Script"));
1303 script_node->add_property (X_("lua"), LUA_VERSION);
1304 script_node->add_content (b64s);
1305 node->add_child_nocopy (*script_node);
1312 Session::get_control_protocol_state ()
1314 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1315 return cpm.get_state();
1319 Session::set_state (const XMLNode& node, int version)
1324 XMLProperty const * prop;
1327 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1329 if (node.name() != X_("Session")) {
1330 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1334 if ((prop = node.property ("name")) != 0) {
1335 _name = prop->value ();
1338 if ((prop = node.property (X_("sample-rate"))) != 0) {
1340 _base_frame_rate = atoi (prop->value());
1341 _nominal_frame_rate = _base_frame_rate;
1343 assert (AudioEngine::instance()->running ());
1344 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1345 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1346 if (r.get_value_or (0)) {
1352 created_with = "unknown";
1353 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1354 if ((prop = child->property (X_("created-with"))) != 0) {
1355 created_with = prop->value ();
1359 setup_raid_path(_session_dir->root_path());
1361 if ((prop = node.property (X_("id-counter"))) != 0) {
1363 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1364 ID::init_counter (x);
1366 /* old sessions used a timebased counter, so fake
1367 the startup ID counter based on a standard
1372 ID::init_counter (now);
1375 if ((prop = node.property (X_("name-counter"))) != 0) {
1376 init_name_id_counter (atoi (prop->value()));
1379 if ((prop = node.property (X_("event-counter"))) != 0) {
1380 Evoral::init_event_id_counter (atoi (prop->value()));
1383 if ((prop = node.property (X_("vca-counter"))) != 0) {
1385 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1386 VCA::set_next_vca_number (x);
1388 VCA::set_next_vca_number (1);
1391 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1392 _midi_ports->set_midi_port_states (child->children());
1395 IO::disable_connecting ();
1397 Stateful::save_extra_xml (node);
1399 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1400 load_options (*child);
1401 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1402 load_options (*child);
1404 error << _("Session: XML state has no options section") << endmsg;
1407 if (version >= 3000) {
1408 if ((child = find_named_node (node, "Metadata")) == 0) {
1409 warning << _("Session: XML state has no metadata section") << endmsg;
1410 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1415 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1416 _speakers->set_state (*child, version);
1419 if ((child = find_named_node (node, "Sources")) == 0) {
1420 error << _("Session: XML state has no sources section") << endmsg;
1422 } else if (load_sources (*child)) {
1426 if ((child = find_named_node (node, "TempoMap")) == 0) {
1427 error << _("Session: XML state has no Tempo Map section") << endmsg;
1429 } else if (_tempo_map->set_state (*child, version)) {
1433 if ((child = find_named_node (node, "Locations")) == 0) {
1434 error << _("Session: XML state has no locations section") << endmsg;
1436 } else if (_locations->set_state (*child, version)) {
1440 locations_changed ();
1442 if (_session_range_location) {
1443 AudioFileSource::set_header_position_offset (_session_range_location->start());
1446 if ((child = find_named_node (node, "Regions")) == 0) {
1447 error << _("Session: XML state has no Regions section") << endmsg;
1449 } else if (load_regions (*child)) {
1453 if ((child = find_named_node (node, "Playlists")) == 0) {
1454 error << _("Session: XML state has no playlists section") << endmsg;
1456 } else if (playlists->load (*this, *child)) {
1460 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1462 } else if (playlists->load_unused (*this, *child)) {
1466 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1467 if (load_compounds (*child)) {
1472 if (version >= 3000) {
1473 if ((child = find_named_node (node, "Bundles")) == 0) {
1474 warning << _("Session: XML state has no bundles section") << endmsg;
1477 /* We can't load Bundles yet as they need to be able
1478 to convert from port names to Port objects, which can't happen until
1480 _bundle_xml_node = new XMLNode (*child);
1484 if (version < 3000) {
1485 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1486 error << _("Session: XML state has no diskstreams section") << endmsg;
1488 } else if (load_diskstreams_2X (*child, version)) {
1493 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1494 _vca_manager->set_state (*child, version);
1497 if ((child = find_named_node (node, "Routes")) == 0) {
1498 error << _("Session: XML state has no routes section") << endmsg;
1500 } else if (load_routes (*child, version)) {
1504 /* Now that we have Routes and masters loaded, connect them if appropriate */
1506 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1508 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1509 _diskstreams_2X.clear ();
1511 if (version >= 3000) {
1513 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1514 error << _("Session: XML state has no route groups section") << endmsg;
1516 } else if (load_route_groups (*child, version)) {
1520 } else if (version < 3000) {
1522 if ((child = find_named_node (node, "EditGroups")) == 0) {
1523 error << _("Session: XML state has no edit groups section") << endmsg;
1525 } else if (load_route_groups (*child, version)) {
1529 if ((child = find_named_node (node, "MixGroups")) == 0) {
1530 error << _("Session: XML state has no mix groups section") << endmsg;
1532 } else if (load_route_groups (*child, version)) {
1537 if ((child = find_named_node (node, "Click")) == 0) {
1538 warning << _("Session: XML state has no click section") << endmsg;
1539 } else if (_click_io) {
1540 setup_click_state (&node);
1543 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1544 ControlProtocolManager::instance().set_state (*child, version);
1547 if ((child = find_named_node (node, "Script"))) {
1548 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1549 if (!(*n)->is_content ()) { continue; }
1551 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1553 Glib::Threads::Mutex::Lock lm (lua_lock);
1554 (*_lua_load)(std::string ((const char*)buf, size));
1555 } catch (luabridge::LuaException const& e) {
1556 cerr << "LuaException:" << e.what () << endl;
1562 update_route_record_state ();
1564 /* here beginneth the second phase ... */
1565 set_snapshot_name (_current_snapshot_name);
1567 StateReady (); /* EMIT SIGNAL */
1580 Session::load_routes (const XMLNode& node, int version)
1583 XMLNodeConstIterator niter;
1584 RouteList new_routes;
1586 nlist = node.children();
1590 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1592 boost::shared_ptr<Route> route;
1593 if (version < 3000) {
1594 route = XMLRouteFactory_2X (**niter, version);
1596 route = XMLRouteFactory (**niter, version);
1600 error << _("Session: cannot create Route from XML description.") << endmsg;
1604 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1606 new_routes.push_back (route);
1609 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1611 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1613 BootMessage (_("Finished adding tracks/busses"));
1618 boost::shared_ptr<Route>
1619 Session::XMLRouteFactory (const XMLNode& node, int version)
1621 boost::shared_ptr<Route> ret;
1623 if (node.name() != "Route") {
1627 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1629 DataType type = DataType::AUDIO;
1630 XMLProperty const * prop = node.property("default-type");
1633 type = DataType (prop->value());
1636 assert (type != DataType::NIL);
1640 boost::shared_ptr<Track> track;
1642 if (type == DataType::AUDIO) {
1643 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1645 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1648 if (track->init()) {
1652 if (track->set_state (node, version)) {
1656 BOOST_MARK_TRACK (track);
1660 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1661 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1663 if (r->init () == 0 && r->set_state (node, version) == 0) {
1664 BOOST_MARK_ROUTE (r);
1672 boost::shared_ptr<Route>
1673 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1675 boost::shared_ptr<Route> ret;
1677 if (node.name() != "Route") {
1681 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1683 ds_prop = node.property (X_("diskstream"));
1686 DataType type = DataType::AUDIO;
1687 XMLProperty const * prop = node.property("default-type");
1690 type = DataType (prop->value());
1693 assert (type != DataType::NIL);
1697 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1698 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1702 if (i == _diskstreams_2X.end()) {
1703 error << _("Could not find diskstream for route") << endmsg;
1704 return boost::shared_ptr<Route> ();
1707 boost::shared_ptr<Track> track;
1709 if (type == DataType::AUDIO) {
1710 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1712 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1715 if (track->init()) {
1719 if (track->set_state (node, version)) {
1723 track->set_diskstream (*i);
1725 BOOST_MARK_TRACK (track);
1729 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1730 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1732 if (r->init () == 0 && r->set_state (node, version) == 0) {
1733 BOOST_MARK_ROUTE (r);
1742 Session::load_regions (const XMLNode& node)
1745 XMLNodeConstIterator niter;
1746 boost::shared_ptr<Region> region;
1748 nlist = node.children();
1752 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1753 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1754 error << _("Session: cannot create Region from XML description.");
1755 XMLProperty const * name = (**niter).property("name");
1758 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1769 Session::load_compounds (const XMLNode& node)
1771 XMLNodeList calist = node.children();
1772 XMLNodeConstIterator caiter;
1773 XMLProperty const * caprop;
1775 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1776 XMLNode* ca = *caiter;
1780 if ((caprop = ca->property (X_("original"))) == 0) {
1783 orig_id = caprop->value();
1785 if ((caprop = ca->property (X_("copy"))) == 0) {
1788 copy_id = caprop->value();
1790 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1791 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1793 if (!orig || !copy) {
1794 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1800 RegionFactory::add_compound_association (orig, copy);
1807 Session::load_nested_sources (const XMLNode& node)
1810 XMLNodeConstIterator niter;
1812 nlist = node.children();
1814 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1815 if ((*niter)->name() == "Source") {
1817 /* it may already exist, so don't recreate it unnecessarily
1820 XMLProperty const * prop = (*niter)->property (X_("id"));
1822 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1826 ID source_id (prop->value());
1828 if (!source_by_id (source_id)) {
1831 SourceFactory::create (*this, **niter, true);
1833 catch (failed_constructor& err) {
1834 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1841 boost::shared_ptr<Region>
1842 Session::XMLRegionFactory (const XMLNode& node, bool full)
1844 XMLProperty const * type = node.property("type");
1848 const XMLNodeList& nlist = node.children();
1850 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1851 XMLNode *child = (*niter);
1852 if (child->name() == "NestedSource") {
1853 load_nested_sources (*child);
1857 if (!type || type->value() == "audio") {
1858 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1859 } else if (type->value() == "midi") {
1860 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1863 } catch (failed_constructor& err) {
1864 return boost::shared_ptr<Region> ();
1867 return boost::shared_ptr<Region> ();
1870 boost::shared_ptr<AudioRegion>
1871 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1873 XMLProperty const * prop;
1874 boost::shared_ptr<Source> source;
1875 boost::shared_ptr<AudioSource> as;
1877 SourceList master_sources;
1878 uint32_t nchans = 1;
1881 if (node.name() != X_("Region")) {
1882 return boost::shared_ptr<AudioRegion>();
1885 if ((prop = node.property (X_("channels"))) != 0) {
1886 nchans = atoi (prop->value().c_str());
1889 if ((prop = node.property ("name")) == 0) {
1890 cerr << "no name for this region\n";
1894 if ((prop = node.property (X_("source-0"))) == 0) {
1895 if ((prop = node.property ("source")) == 0) {
1896 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1897 return boost::shared_ptr<AudioRegion>();
1901 PBD::ID s_id (prop->value());
1903 if ((source = source_by_id (s_id)) == 0) {
1904 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1905 return boost::shared_ptr<AudioRegion>();
1908 as = boost::dynamic_pointer_cast<AudioSource>(source);
1910 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1911 return boost::shared_ptr<AudioRegion>();
1914 sources.push_back (as);
1916 /* pickup other channels */
1918 for (uint32_t n=1; n < nchans; ++n) {
1919 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1920 if ((prop = node.property (buf)) != 0) {
1922 PBD::ID id2 (prop->value());
1924 if ((source = source_by_id (id2)) == 0) {
1925 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1926 return boost::shared_ptr<AudioRegion>();
1929 as = boost::dynamic_pointer_cast<AudioSource>(source);
1931 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1932 return boost::shared_ptr<AudioRegion>();
1934 sources.push_back (as);
1938 for (uint32_t n = 0; n < nchans; ++n) {
1939 snprintf (buf, sizeof(buf), X_("master-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 master_sources.push_back (as);
1959 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1961 /* a final detail: this is the one and only place that we know how long missing files are */
1963 if (region->whole_file()) {
1964 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1965 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1967 sfp->set_length (region->length());
1972 if (!master_sources.empty()) {
1973 if (master_sources.size() != nchans) {
1974 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1976 region->set_master_sources (master_sources);
1984 catch (failed_constructor& err) {
1985 return boost::shared_ptr<AudioRegion>();
1989 boost::shared_ptr<MidiRegion>
1990 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1992 XMLProperty const * prop;
1993 boost::shared_ptr<Source> source;
1994 boost::shared_ptr<MidiSource> ms;
1997 if (node.name() != X_("Region")) {
1998 return boost::shared_ptr<MidiRegion>();
2001 if ((prop = node.property ("name")) == 0) {
2002 cerr << "no name for this region\n";
2006 if ((prop = node.property (X_("source-0"))) == 0) {
2007 if ((prop = node.property ("source")) == 0) {
2008 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2009 return boost::shared_ptr<MidiRegion>();
2013 PBD::ID s_id (prop->value());
2015 if ((source = source_by_id (s_id)) == 0) {
2016 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2017 return boost::shared_ptr<MidiRegion>();
2020 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2022 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2023 return boost::shared_ptr<MidiRegion>();
2026 sources.push_back (ms);
2029 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2030 /* a final detail: this is the one and only place that we know how long missing files are */
2032 if (region->whole_file()) {
2033 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2034 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2036 sfp->set_length (region->length());
2044 catch (failed_constructor& err) {
2045 return boost::shared_ptr<MidiRegion>();
2050 Session::get_sources_as_xml ()
2053 XMLNode* node = new XMLNode (X_("Sources"));
2054 Glib::Threads::Mutex::Lock lm (source_lock);
2056 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2057 node->add_child_nocopy (i->second->get_state());
2064 Session::reset_write_sources (bool mark_write_complete, bool force)
2066 boost::shared_ptr<RouteList> rl = routes.reader();
2067 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2068 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2070 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2071 tr->reset_write_sources(mark_write_complete, force);
2072 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2078 Session::load_sources (const XMLNode& node)
2081 XMLNodeConstIterator niter;
2082 boost::shared_ptr<Source> source; /* don't need this but it stops some
2083 * versions of gcc complaining about
2084 * discarded return values.
2087 nlist = node.children();
2091 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2094 if ((source = XMLSourceFactory (**niter)) == 0) {
2095 error << _("Session: cannot create Source from XML description.") << endmsg;
2098 } catch (MissingSource& err) {
2102 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2103 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2104 PROGRAM_NAME) << endmsg;
2108 if (!no_questions_about_missing_files) {
2109 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2114 switch (user_choice) {
2116 /* user added a new search location, so try again */
2121 /* user asked to quit the entire session load
2126 no_questions_about_missing_files = true;
2130 no_questions_about_missing_files = true;
2137 case DataType::AUDIO:
2138 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2141 case DataType::MIDI:
2142 /* The MIDI file is actually missing so
2143 * just create a new one in the same
2144 * location. Do not announce its
2148 if (!Glib::path_is_absolute (err.path)) {
2149 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2151 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2156 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2157 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2158 /* reset ID to match the missing one */
2159 source->set_id (**niter);
2160 /* Now we can announce it */
2161 SourceFactory::SourceCreated (source);
2172 boost::shared_ptr<Source>
2173 Session::XMLSourceFactory (const XMLNode& node)
2175 if (node.name() != "Source") {
2176 return boost::shared_ptr<Source>();
2180 /* note: do peak building in another thread when loading session state */
2181 return SourceFactory::create (*this, node, true);
2184 catch (failed_constructor& err) {
2185 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2186 return boost::shared_ptr<Source>();
2191 Session::save_template (string template_name, bool replace_existing)
2193 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2197 bool absolute_path = Glib::path_is_absolute (template_name);
2199 /* directory to put the template in */
2200 std::string template_dir_path;
2202 if (!absolute_path) {
2203 std::string user_template_dir(user_template_directory());
2205 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2206 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2207 user_template_dir, g_strerror (errno)) << endmsg;
2211 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2213 template_dir_path = template_name;
2216 if (!ARDOUR::Profile->get_trx()) {
2217 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2218 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2219 template_dir_path) << endmsg;
2223 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2224 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2225 template_dir_path, g_strerror (errno)) << endmsg;
2231 std::string template_file_path;
2233 if (ARDOUR::Profile->get_trx()) {
2234 template_file_path = template_name;
2236 if (absolute_path) {
2237 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2239 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2243 SessionSaveUnderway (); /* EMIT SIGNAL */
2248 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2249 tree.set_root (&get_template());
2252 if (!tree.write (template_file_path)) {
2253 error << _("template not saved") << endmsg;
2257 store_recent_templates (template_file_path);
2263 Session::refresh_disk_space ()
2265 #if __APPLE__ || __FreeBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2267 Glib::Threads::Mutex::Lock lm (space_lock);
2269 /* get freespace on every FS that is part of the session path */
2271 _total_free_4k_blocks = 0;
2272 _total_free_4k_blocks_uncertain = false;
2274 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2276 struct statfs statfsbuf;
2277 statfs (i->path.c_str(), &statfsbuf);
2279 double const scale = statfsbuf.f_bsize / 4096.0;
2281 /* See if this filesystem is read-only */
2282 struct statvfs statvfsbuf;
2283 statvfs (i->path.c_str(), &statvfsbuf);
2285 /* f_bavail can be 0 if it is undefined for whatever
2286 filesystem we are looking at; Samba shares mounted
2287 via GVFS are an example of this.
2289 if (statfsbuf.f_bavail == 0) {
2290 /* block count unknown */
2292 i->blocks_unknown = true;
2293 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2294 /* read-only filesystem */
2296 i->blocks_unknown = false;
2298 /* read/write filesystem with known space */
2299 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2300 i->blocks_unknown = false;
2303 _total_free_4k_blocks += i->blocks;
2304 if (i->blocks_unknown) {
2305 _total_free_4k_blocks_uncertain = true;
2308 #elif defined PLATFORM_WINDOWS
2309 vector<string> scanned_volumes;
2310 vector<string>::iterator j;
2311 vector<space_and_path>::iterator i;
2312 DWORD nSectorsPerCluster, nBytesPerSector,
2313 nFreeClusters, nTotalClusters;
2317 _total_free_4k_blocks = 0;
2319 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2320 strncpy (disk_drive, (*i).path.c_str(), 3);
2324 volume_found = false;
2325 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2327 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2328 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2329 i->blocks = (uint32_t)(nFreeBytes / 4096);
2331 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2332 if (0 == j->compare(disk_drive)) {
2333 volume_found = true;
2338 if (!volume_found) {
2339 scanned_volumes.push_back(disk_drive);
2340 _total_free_4k_blocks += i->blocks;
2345 if (0 == _total_free_4k_blocks) {
2346 strncpy (disk_drive, path().c_str(), 3);
2349 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2351 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2352 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2353 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2360 Session::get_best_session_directory_for_new_audio ()
2362 vector<space_and_path>::iterator i;
2363 string result = _session_dir->root_path();
2365 /* handle common case without system calls */
2367 if (session_dirs.size() == 1) {
2371 /* OK, here's the algorithm we're following here:
2373 We want to select which directory to use for
2374 the next file source to be created. Ideally,
2375 we'd like to use a round-robin process so as to
2376 get maximum performance benefits from splitting
2377 the files across multiple disks.
2379 However, in situations without much diskspace, an
2380 RR approach may end up filling up a filesystem
2381 with new files while others still have space.
2382 Its therefore important to pay some attention to
2383 the freespace in the filesystem holding each
2384 directory as well. However, if we did that by
2385 itself, we'd keep creating new files in the file
2386 system with the most space until it was as full
2387 as all others, thus negating any performance
2388 benefits of this RAID-1 like approach.
2390 So, we use a user-configurable space threshold. If
2391 there are at least 2 filesystems with more than this
2392 much space available, we use RR selection between them.
2393 If not, then we pick the filesystem with the most space.
2395 This gets a good balance between the two
2399 refresh_disk_space ();
2401 int free_enough = 0;
2403 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2404 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2409 if (free_enough >= 2) {
2410 /* use RR selection process, ensuring that the one
2414 i = last_rr_session_dir;
2417 if (++i == session_dirs.end()) {
2418 i = session_dirs.begin();
2421 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2422 SessionDirectory sdir(i->path);
2423 if (sdir.create ()) {
2425 last_rr_session_dir = i;
2430 } while (i != last_rr_session_dir);
2434 /* pick FS with the most freespace (and that
2435 seems to actually work ...)
2438 vector<space_and_path> sorted;
2439 space_and_path_ascending_cmp cmp;
2441 sorted = session_dirs;
2442 sort (sorted.begin(), sorted.end(), cmp);
2444 for (i = sorted.begin(); i != sorted.end(); ++i) {
2445 SessionDirectory sdir(i->path);
2446 if (sdir.create ()) {
2448 last_rr_session_dir = i;
2458 Session::automation_dir () const
2460 return Glib::build_filename (_path, automation_dir_name);
2464 Session::analysis_dir () const
2466 return Glib::build_filename (_path, analysis_dir_name);
2470 Session::plugins_dir () const
2472 return Glib::build_filename (_path, plugins_dir_name);
2476 Session::externals_dir () const
2478 return Glib::build_filename (_path, externals_dir_name);
2482 Session::load_bundles (XMLNode const & node)
2484 XMLNodeList nlist = node.children();
2485 XMLNodeConstIterator niter;
2489 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2490 if ((*niter)->name() == "InputBundle") {
2491 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2492 } else if ((*niter)->name() == "OutputBundle") {
2493 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2495 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2504 Session::load_route_groups (const XMLNode& node, int version)
2506 XMLNodeList nlist = node.children();
2507 XMLNodeConstIterator niter;
2511 if (version >= 3000) {
2513 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2514 if ((*niter)->name() == "RouteGroup") {
2515 RouteGroup* rg = new RouteGroup (*this, "");
2516 add_route_group (rg);
2517 rg->set_state (**niter, version);
2521 } else if (version < 3000) {
2523 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2524 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2525 RouteGroup* rg = new RouteGroup (*this, "");
2526 add_route_group (rg);
2527 rg->set_state (**niter, version);
2536 state_file_filter (const string &str, void* /*arg*/)
2538 return (str.length() > strlen(statefile_suffix) &&
2539 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2543 remove_end(string state)
2545 string statename(state);
2547 string::size_type start,end;
2548 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2549 statename = statename.substr (start+1);
2552 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2553 end = statename.length();
2556 return string(statename.substr (0, end));
2560 Session::possible_states (string path)
2562 vector<string> states;
2563 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2565 transform(states.begin(), states.end(), states.begin(), remove_end);
2567 sort (states.begin(), states.end());
2573 Session::possible_states () const
2575 return possible_states(_path);
2579 Session::add_route_group (RouteGroup* g)
2581 _route_groups.push_back (g);
2582 route_group_added (g); /* EMIT SIGNAL */
2584 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2585 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2586 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2592 Session::remove_route_group (RouteGroup& rg)
2594 list<RouteGroup*>::iterator i;
2596 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2597 _route_groups.erase (i);
2600 route_group_removed (); /* EMIT SIGNAL */
2604 /** Set a new order for our route groups, without adding or removing any.
2605 * @param groups Route group list in the new order.
2608 Session::reorder_route_groups (list<RouteGroup*> groups)
2610 _route_groups = groups;
2612 route_groups_reordered (); /* EMIT SIGNAL */
2618 Session::route_group_by_name (string name)
2620 list<RouteGroup *>::iterator i;
2622 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2623 if ((*i)->name() == name) {
2631 Session::all_route_group() const
2633 return *_all_route_group;
2637 Session::add_commands (vector<Command*> const & cmds)
2639 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2645 Session::add_command (Command* const cmd)
2647 assert (_current_trans);
2648 DEBUG_UNDO_HISTORY (
2649 string_compose ("Current Undo Transaction %1, adding command: %2",
2650 _current_trans->name (),
2652 _current_trans->add_command (cmd);
2655 PBD::StatefulDiffCommand*
2656 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2658 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2664 Session::begin_reversible_command (const string& name)
2666 begin_reversible_command (g_quark_from_string (name.c_str ()));
2669 /** Begin a reversible command using a GQuark to identify it.
2670 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2671 * but there must be as many begin...()s as there are commit...()s.
2674 Session::begin_reversible_command (GQuark q)
2676 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2677 to hold all the commands that are committed. This keeps the order of
2678 commands correct in the history.
2681 if (_current_trans == 0) {
2682 DEBUG_UNDO_HISTORY (string_compose (
2683 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2685 /* start a new transaction */
2686 assert (_current_trans_quarks.empty ());
2687 _current_trans = new UndoTransaction();
2688 _current_trans->set_name (g_quark_to_string (q));
2690 DEBUG_UNDO_HISTORY (
2691 string_compose ("Begin Reversible Command, current transaction: %1",
2692 _current_trans->name ()));
2695 _current_trans_quarks.push_front (q);
2699 Session::abort_reversible_command ()
2701 if (_current_trans != 0) {
2702 DEBUG_UNDO_HISTORY (
2703 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2704 _current_trans->clear();
2705 delete _current_trans;
2707 _current_trans_quarks.clear();
2712 Session::commit_reversible_command (Command *cmd)
2714 assert (_current_trans);
2715 assert (!_current_trans_quarks.empty ());
2720 DEBUG_UNDO_HISTORY (
2721 string_compose ("Current Undo Transaction %1, adding command: %2",
2722 _current_trans->name (),
2724 _current_trans->add_command (cmd);
2727 DEBUG_UNDO_HISTORY (
2728 string_compose ("Commit Reversible Command, current transaction: %1",
2729 _current_trans->name ()));
2731 _current_trans_quarks.pop_front ();
2733 if (!_current_trans_quarks.empty ()) {
2734 DEBUG_UNDO_HISTORY (
2735 string_compose ("Commit Reversible Command, transaction is not "
2736 "top-level, current transaction: %1",
2737 _current_trans->name ()));
2738 /* the transaction we're committing is not the top-level one */
2742 if (_current_trans->empty()) {
2743 /* no commands were added to the transaction, so just get rid of it */
2744 DEBUG_UNDO_HISTORY (
2745 string_compose ("Commit Reversible Command, No commands were "
2746 "added to current transaction: %1",
2747 _current_trans->name ()));
2748 delete _current_trans;
2753 gettimeofday (&now, 0);
2754 _current_trans->set_timestamp (now);
2756 _history.add (_current_trans);
2761 accept_all_audio_files (const string& path, void* /*arg*/)
2763 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2767 if (!AudioFileSource::safe_audio_file_extension (path)) {
2775 accept_all_midi_files (const string& path, void* /*arg*/)
2777 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2781 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2782 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2783 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2787 accept_all_state_files (const string& path, void* /*arg*/)
2789 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2793 std::string const statefile_ext (statefile_suffix);
2794 if (path.length() >= statefile_ext.length()) {
2795 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2802 Session::find_all_sources (string path, set<string>& result)
2807 if (!tree.read (path)) {
2811 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2816 XMLNodeConstIterator niter;
2818 nlist = node->children();
2822 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2824 XMLProperty const * prop;
2826 if ((prop = (*niter)->property (X_("type"))) == 0) {
2830 DataType type (prop->value());
2832 if ((prop = (*niter)->property (X_("name"))) == 0) {
2836 if (Glib::path_is_absolute (prop->value())) {
2837 /* external file, ignore */
2845 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2846 result.insert (found_path);
2854 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2856 vector<string> state_files;
2858 string this_snapshot_path;
2864 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2865 ripped = ripped.substr (0, ripped.length() - 1);
2868 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2870 if (state_files.empty()) {
2875 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2876 this_snapshot_path += statefile_suffix;
2878 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2880 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2882 if (exclude_this_snapshot && *i == this_snapshot_path) {
2883 cerr << "\texcluded\n";
2888 if (find_all_sources (*i, result) < 0) {
2896 struct RegionCounter {
2897 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2898 AudioSourceList::iterator iter;
2899 boost::shared_ptr<Region> region;
2902 RegionCounter() : count (0) {}
2906 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2908 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2909 return r.get_value_or (1);
2913 Session::cleanup_regions ()
2915 bool removed = false;
2916 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2918 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2920 uint32_t used = playlists->region_use_count (i->second);
2922 if (used == 0 && !i->second->automatic ()) {
2923 boost::weak_ptr<Region> w = i->second;
2926 RegionFactory::map_remove (w);
2933 // re-check to remove parent references of compound regions
2934 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2935 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2939 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2940 if (0 == playlists->region_use_count (i->second)) {
2941 boost::weak_ptr<Region> w = i->second;
2943 RegionFactory::map_remove (w);
2950 /* dump the history list */
2957 Session::can_cleanup_peakfiles () const
2959 if (deletion_in_progress()) {
2962 if (!_writable || (_state_of_the_state & CannotSave)) {
2963 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2966 if (record_status() == Recording) {
2967 error << _("Cannot cleanup peak-files while recording") << endmsg;
2974 Session::cleanup_peakfiles ()
2976 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2981 assert (can_cleanup_peakfiles ());
2982 assert (!peaks_cleanup_in_progres());
2984 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2986 int timeout = 5000; // 5 seconds
2987 while (!SourceFactory::files_with_peaks.empty()) {
2988 Glib::usleep (1000);
2989 if (--timeout < 0) {
2990 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2991 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2996 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2997 boost::shared_ptr<AudioSource> as;
2998 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2999 as->close_peakfile();
3003 PBD::clear_directory (session_directory().peak_path());
3005 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3007 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3008 boost::shared_ptr<AudioSource> as;
3009 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3010 SourceFactory::setup_peakfile(as, true);
3017 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3019 pl->deep_sources (*all_sources);
3023 Session::cleanup_sources (CleanupReport& rep)
3025 // FIXME: needs adaptation to midi
3027 vector<boost::shared_ptr<Source> > dead_sources;
3030 vector<string> candidates;
3031 vector<string> unused;
3032 set<string> sources_used_by_all_snapshots;
3039 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3041 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3043 /* this is mostly for windows which doesn't allow file
3044 * renaming if the file is in use. But we don't special
3045 * case it because we need to know if this causes
3046 * problems, and the easiest way to notice that is to
3047 * keep it in place for all platforms.
3050 request_stop (false);
3052 _butler->wait_until_finished ();
3054 /* consider deleting all unused playlists */
3056 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3061 /* sync the "all regions" property of each playlist with its current state
3064 playlists->sync_all_regions_with_regions ();
3066 /* find all un-used sources */
3071 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3073 SourceMap::iterator tmp;
3078 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3082 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3083 dead_sources.push_back (i->second);
3084 i->second->drop_references ();
3090 /* build a list of all the possible audio directories for the session */
3092 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3093 SessionDirectory sdir ((*i).path);
3094 asp += sdir.sound_path();
3096 audio_path += asp.to_string();
3099 /* build a list of all the possible midi directories for the session */
3101 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3102 SessionDirectory sdir ((*i).path);
3103 msp += sdir.midi_path();
3105 midi_path += msp.to_string();
3107 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3108 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3110 /* add sources from all other snapshots as "used", but don't use this
3111 snapshot because the state file on disk still references sources we
3112 may have already dropped.
3115 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3117 /* Although the region factory has a list of all regions ever created
3118 * for this session, we're only interested in regions actually in
3119 * playlists right now. So merge all playlist regions lists together.
3121 * This will include the playlists used within compound regions.
3124 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3126 /* add our current source list
3129 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3130 boost::shared_ptr<FileSource> fs;
3131 SourceMap::iterator tmp = i;
3134 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3140 /* this is mostly for windows which doesn't allow file
3141 * renaming if the file is in use. But we do not special
3142 * case it because we need to know if this causes
3143 * problems, and the easiest way to notice that is to
3144 * keep it in place for all platforms.
3149 if (!fs->is_stub()) {
3151 /* Note that we're checking a list of all
3152 * sources across all snapshots with the list
3153 * of sources used by this snapshot.
3156 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3157 /* this source is in use by this snapshot */
3158 sources_used_by_all_snapshots.insert (fs->path());
3159 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3161 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3162 /* this source is NOT in use by this snapshot
3165 /* remove all related regions from RegionFactory master list
3168 RegionFactory::remove_regions_using_source (i->second);
3170 /* remove from our current source list
3171 * also. We may not remove it from
3172 * disk, because it may be used by
3173 * other snapshots, but it isn't used inside this
3174 * snapshot anymore, so we don't need a
3185 /* now check each candidate source to see if it exists in the list of
3186 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3189 cerr << "Candidates: " << candidates.size() << endl;
3190 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3192 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3197 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3199 tmppath1 = canonical_path (spath);
3200 tmppath2 = canonical_path ((*i));
3202 cerr << "\t => " << tmppath2 << endl;
3204 if (tmppath1 == tmppath2) {
3211 unused.push_back (spath);
3215 cerr << "Actually unused: " << unused.size() << endl;
3217 if (unused.empty()) {
3223 /* now try to move all unused files into the "dead" directory(ies) */
3225 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3230 /* don't move the file across filesystems, just
3231 stick it in the `dead_dir_name' directory
3232 on whichever filesystem it was already on.
3235 if ((*x).find ("/sounds/") != string::npos) {
3237 /* old school, go up 1 level */
3239 newpath = Glib::path_get_dirname (*x); // "sounds"
3240 newpath = Glib::path_get_dirname (newpath); // "session-name"
3244 /* new school, go up 4 levels */
3246 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3247 newpath = Glib::path_get_dirname (newpath); // "session-name"
3248 newpath = Glib::path_get_dirname (newpath); // "interchange"
3249 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3252 newpath = Glib::build_filename (newpath, dead_dir_name);
3254 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3255 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3259 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3261 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3263 /* the new path already exists, try versioning */
3265 char buf[PATH_MAX+1];
3269 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3272 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3273 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3277 if (version == 999) {
3278 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3282 newpath = newpath_v;
3287 g_stat ((*x).c_str(), &statbuf);
3289 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3290 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x), newpath, strerror (errno)) << endmsg;
3294 /* see if there an easy to find peakfile for this file, and remove it.
3297 string base = Glib::path_get_basename (*x);
3298 base += "%A"; /* this is what we add for the channel suffix of all native files,
3299 or for the first channel of embedded files. it will miss
3300 some peakfiles for other channels
3302 string peakpath = construct_peak_filepath (base);
3304 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3305 if (::g_unlink (peakpath.c_str()) != 0) {
3306 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3307 peakpath, _path, strerror (errno))
3309 /* try to back out */
3310 ::rename (newpath.c_str(), _path.c_str());
3315 rep.paths.push_back (*x);
3316 rep.space += statbuf.st_size;
3319 /* dump the history list */
3323 /* save state so we don't end up a session file
3324 referring to non-existent sources.
3331 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3337 Session::cleanup_trash_sources (CleanupReport& rep)
3339 // FIXME: needs adaptation for MIDI
3341 vector<space_and_path>::iterator i;
3347 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3349 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3351 clear_directory (dead_dir, &rep.space, &rep.paths);
3358 Session::set_dirty ()
3360 /* never mark session dirty during loading */
3362 if (_state_of_the_state & Loading) {
3366 bool was_dirty = dirty();
3368 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3372 DirtyChanged(); /* EMIT SIGNAL */
3378 Session::set_clean ()
3380 bool was_dirty = dirty();
3382 _state_of_the_state = Clean;
3386 DirtyChanged(); /* EMIT SIGNAL */
3391 Session::set_deletion_in_progress ()
3393 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3397 Session::clear_deletion_in_progress ()
3399 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3403 Session::add_controllable (boost::shared_ptr<Controllable> c)
3405 /* this adds a controllable to the list managed by the Session.
3406 this is a subset of those managed by the Controllable class
3407 itself, and represents the only ones whose state will be saved
3408 as part of the session.
3411 Glib::Threads::Mutex::Lock lm (controllables_lock);
3412 controllables.insert (c);
3415 struct null_deleter { void operator()(void const *) const {} };
3418 Session::remove_controllable (Controllable* c)
3420 if (_state_of_the_state & Deletion) {
3424 Glib::Threads::Mutex::Lock lm (controllables_lock);
3426 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3428 if (x != controllables.end()) {
3429 controllables.erase (x);
3433 boost::shared_ptr<Controllable>
3434 Session::controllable_by_id (const PBD::ID& id)
3436 Glib::Threads::Mutex::Lock lm (controllables_lock);
3438 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3439 if ((*i)->id() == id) {
3444 return boost::shared_ptr<Controllable>();
3447 boost::shared_ptr<Controllable>
3448 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3450 boost::shared_ptr<Controllable> c;
3451 boost::shared_ptr<Stripable> s;
3452 boost::shared_ptr<Route> r;
3454 switch (desc.top_level_type()) {
3455 case ControllableDescriptor::NamedRoute:
3457 std::string str = desc.top_level_name();
3459 if (str == "Master" || str == "master") {
3461 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3463 } else if (str == "auditioner") {
3466 s = route_by_name (desc.top_level_name());
3472 case ControllableDescriptor::PresentationOrderRoute:
3473 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3476 case ControllableDescriptor::PresentationOrderTrack:
3477 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3480 case ControllableDescriptor::PresentationOrderBus:
3481 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3484 case ControllableDescriptor::PresentationOrderVCA:
3485 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3488 case ControllableDescriptor::SelectionCount:
3489 s = route_by_selected_count (desc.selection_id());
3497 r = boost::dynamic_pointer_cast<Route> (s);
3499 switch (desc.subtype()) {
3500 case ControllableDescriptor::Gain:
3501 c = s->gain_control ();
3504 case ControllableDescriptor::Trim:
3505 c = s->trim_control ();
3508 case ControllableDescriptor::Solo:
3509 c = s->solo_control();
3512 case ControllableDescriptor::Mute:
3513 c = s->mute_control();
3516 case ControllableDescriptor::Recenable:
3517 c = s->rec_enable_control ();
3520 case ControllableDescriptor::PanDirection:
3521 c = s->pan_azimuth_control();
3524 case ControllableDescriptor::PanWidth:
3525 c = s->pan_width_control();
3528 case ControllableDescriptor::PanElevation:
3529 c = s->pan_elevation_control();
3532 case ControllableDescriptor::Balance:
3533 /* XXX simple pan control */
3536 case ControllableDescriptor::PluginParameter:
3538 uint32_t plugin = desc.target (0);
3539 uint32_t parameter_index = desc.target (1);
3541 /* revert to zero based counting */
3547 if (parameter_index > 0) {
3555 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3558 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3559 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3564 case ControllableDescriptor::SendGain: {
3565 uint32_t send = desc.target (0);
3572 c = r->send_level_controllable (send);
3577 /* relax and return a null pointer */
3585 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3588 Stateful::add_instant_xml (node, _path);
3591 if (write_to_config) {
3592 Config->add_instant_xml (node);
3597 Session::instant_xml (const string& node_name)
3599 return Stateful::instant_xml (node_name, _path);
3603 Session::save_history (string snapshot_name)
3611 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3612 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3616 if (snapshot_name.empty()) {
3617 snapshot_name = _current_snapshot_name;
3620 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3621 const string backup_filename = history_filename + backup_suffix;
3622 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3623 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3625 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3626 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3627 error << _("could not backup old history file, current history not saved") << endmsg;
3632 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3634 if (!tree.write (xml_path))
3636 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3638 if (g_remove (xml_path.c_str()) != 0) {
3639 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3640 xml_path, g_strerror (errno)) << endmsg;
3642 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3643 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3644 backup_path, g_strerror (errno)) << endmsg;
3654 Session::restore_history (string snapshot_name)
3658 if (snapshot_name.empty()) {
3659 snapshot_name = _current_snapshot_name;
3662 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3663 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3665 info << "Loading history from " << xml_path << endmsg;
3667 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3668 info << string_compose (_("%1: no history file \"%2\" for this session."),
3669 _name, xml_path) << endmsg;
3673 if (!tree.read (xml_path)) {
3674 error << string_compose (_("Could not understand session history file \"%1\""),
3675 xml_path) << endmsg;
3682 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3685 UndoTransaction* ut = new UndoTransaction ();
3688 ut->set_name(t->property("name")->value());
3689 stringstream ss(t->property("tv-sec")->value());
3691 ss.str(t->property("tv-usec")->value());
3693 ut->set_timestamp(tv);
3695 for (XMLNodeConstIterator child_it = t->children().begin();
3696 child_it != t->children().end(); child_it++)
3698 XMLNode *n = *child_it;
3701 if (n->name() == "MementoCommand" ||
3702 n->name() == "MementoUndoCommand" ||
3703 n->name() == "MementoRedoCommand") {
3705 if ((c = memento_command_factory(n))) {
3709 } else if (n->name() == "NoteDiffCommand") {
3710 PBD::ID id (n->property("midi-source")->value());
3711 boost::shared_ptr<MidiSource> midi_source =
3712 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3714 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3716 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3719 } else if (n->name() == "SysExDiffCommand") {
3721 PBD::ID id (n->property("midi-source")->value());
3722 boost::shared_ptr<MidiSource> midi_source =
3723 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3725 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3727 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3730 } else if (n->name() == "PatchChangeDiffCommand") {
3732 PBD::ID id (n->property("midi-source")->value());
3733 boost::shared_ptr<MidiSource> midi_source =
3734 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3736 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3738 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3741 } else if (n->name() == "StatefulDiffCommand") {
3742 if ((c = stateful_diff_command_factory (n))) {
3743 ut->add_command (c);
3746 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3757 Session::config_changed (std::string p, bool ours)
3763 if (p == "seamless-loop") {
3765 } else if (p == "rf-speed") {
3767 } else if (p == "auto-loop") {
3769 } else if (p == "auto-input") {
3771 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3772 /* auto-input only makes a difference if we're rolling */
3773 set_track_monitor_input_status (!config.get_auto_input());
3776 } else if (p == "punch-in") {
3780 if ((location = _locations->auto_punch_location()) != 0) {
3782 if (config.get_punch_in ()) {
3783 replace_event (SessionEvent::PunchIn, location->start());
3785 remove_event (location->start(), SessionEvent::PunchIn);
3789 } else if (p == "punch-out") {
3793 if ((location = _locations->auto_punch_location()) != 0) {
3795 if (config.get_punch_out()) {
3796 replace_event (SessionEvent::PunchOut, location->end());
3798 clear_events (SessionEvent::PunchOut);
3802 } else if (p == "edit-mode") {
3804 Glib::Threads::Mutex::Lock lm (playlists->lock);
3806 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3807 (*i)->set_edit_mode (Config->get_edit_mode ());
3810 } else if (p == "use-video-sync") {
3812 waiting_for_sync_offset = config.get_use_video_sync();
3814 } else if (p == "mmc-control") {
3816 //poke_midi_thread ();
3818 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3820 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3822 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3824 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3826 } else if (p == "midi-control") {
3828 //poke_midi_thread ();
3830 } else if (p == "raid-path") {
3832 setup_raid_path (config.get_raid_path());
3834 } else if (p == "timecode-format") {
3838 } else if (p == "video-pullup") {
3842 } else if (p == "seamless-loop") {
3844 if (play_loop && transport_rolling()) {
3845 // to reset diskstreams etc
3846 request_play_loop (true);
3849 } else if (p == "rf-speed") {
3851 cumulative_rf_motion = 0;
3854 } else if (p == "click-sound") {
3856 setup_click_sounds (1);
3858 } else if (p == "click-emphasis-sound") {
3860 setup_click_sounds (-1);
3862 } else if (p == "clicking") {
3864 if (Config->get_clicking()) {
3865 if (_click_io && click_data) { // don't require emphasis data
3872 } else if (p == "click-gain") {
3875 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3878 } else if (p == "send-mtc") {
3880 if (Config->get_send_mtc ()) {
3881 /* mark us ready to send */
3882 next_quarter_frame_to_send = 0;
3885 } else if (p == "send-mmc") {
3887 _mmc->enable_send (Config->get_send_mmc ());
3889 } else if (p == "midi-feedback") {
3891 session_midi_feedback = Config->get_midi_feedback();
3893 } else if (p == "jack-time-master") {
3895 engine().reset_timebase ();
3897 } else if (p == "native-file-header-format") {
3899 if (!first_file_header_format_reset) {
3900 reset_native_file_format ();
3903 first_file_header_format_reset = false;
3905 } else if (p == "native-file-data-format") {
3907 if (!first_file_data_format_reset) {
3908 reset_native_file_format ();
3911 first_file_data_format_reset = false;
3913 } else if (p == "external-sync") {
3914 if (!config.get_external_sync()) {
3915 drop_sync_source ();
3917 switch_to_sync_source (Config->get_sync_source());
3919 } else if (p == "denormal-model") {
3921 } else if (p == "history-depth") {
3922 set_history_depth (Config->get_history_depth());
3923 } else if (p == "remote-model") {
3924 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3927 } else if (p == "initial-program-change") {
3929 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3932 buf[0] = MIDI::program; // channel zero by default
3933 buf[1] = (Config->get_initial_program_change() & 0x7f);
3935 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3937 } else if (p == "solo-mute-override") {
3938 // catch_up_on_solo_mute_override ();
3939 } else if (p == "listen-position" || p == "pfl-position") {
3940 listen_position_changed ();
3941 } else if (p == "solo-control-is-listen-control") {
3942 solo_control_mode_changed ();
3943 } else if (p == "solo-mute-gain") {
3944 _solo_cut_control->Changed (true, Controllable::NoGroup);
3945 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3946 last_timecode_valid = false;
3947 } else if (p == "playback-buffer-seconds") {
3948 AudioSource::allocate_working_buffers (frame_rate());
3949 } else if (p == "ltc-source-port") {
3950 reconnect_ltc_input ();
3951 } else if (p == "ltc-sink-port") {
3952 reconnect_ltc_output ();
3953 } else if (p == "timecode-generator-offset") {
3954 ltc_tx_parse_offset();
3955 } else if (p == "auto-return-target-list") {
3956 follow_playhead_priority ();
3963 Session::set_history_depth (uint32_t d)
3965 _history.set_depth (d);
3969 Session::load_diskstreams_2X (XMLNode const & node, int)
3972 XMLNodeConstIterator citer;
3974 clist = node.children();
3976 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3979 /* diskstreams added automatically by DiskstreamCreated handler */
3980 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3981 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3982 _diskstreams_2X.push_back (dsp);
3984 error << _("Session: unknown diskstream type in XML") << endmsg;
3988 catch (failed_constructor& err) {
3989 error << _("Session: could not load diskstream via XML state") << endmsg;
3997 /** Connect things to the MMC object */
3999 Session::setup_midi_machine_control ()
4001 _mmc = new MIDI::MachineControl;
4003 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4004 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4006 if (!async_out || !async_out) {
4010 /* XXXX argh, passing raw pointers back into libmidi++ */
4012 MIDI::Port* mmc_in = async_in.get();
4013 MIDI::Port* mmc_out = async_out.get();
4015 _mmc->set_ports (mmc_in, mmc_out);
4017 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4018 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4019 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4020 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4021 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4022 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4023 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4024 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4025 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4026 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4027 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4028 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4029 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4031 /* also handle MIDI SPP because its so common */
4033 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4034 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4035 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4038 boost::shared_ptr<Controllable>
4039 Session::solo_cut_control() const
4041 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4042 controls in Ardour that currently get presented to the user in the GUI that require
4043 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4045 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4046 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4050 return _solo_cut_control;
4054 Session::save_snapshot_name (const std::string & n)
4056 /* assure Stateful::_instant_xml is loaded
4057 * add_instant_xml() only adds to existing data and defaults
4058 * to use an empty Tree otherwise
4060 instant_xml ("LastUsedSnapshot");
4062 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4063 last_used_snapshot->add_property ("name", string(n));
4064 add_instant_xml (*last_used_snapshot, false);
4068 Session::set_snapshot_name (const std::string & n)
4070 _current_snapshot_name = n;
4071 save_snapshot_name (n);
4075 Session::rename (const std::string& new_name)
4077 string legal_name = legalize_for_path (new_name);
4083 string const old_sources_root = _session_dir->sources_root();
4085 if (!_writable || (_state_of_the_state & CannotSave)) {
4086 error << _("Cannot rename read-only session.") << endmsg;
4087 return 0; // don't show "messed up" warning
4089 if (record_status() == Recording) {
4090 error << _("Cannot rename session while recording") << endmsg;
4091 return 0; // don't show "messed up" warning
4094 StateProtector stp (this);
4099 * interchange subdirectory
4103 * Backup files are left unchanged and not renamed.
4106 /* Windows requires that we close all files before attempting the
4107 * rename. This works on other platforms, but isn't necessary there.
4108 * Leave it in place for all platforms though, since it may help
4109 * catch issues that could arise if the way Source files work ever
4110 * change (since most developers are not using Windows).
4113 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4114 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4120 /* pass one: not 100% safe check that the new directory names don't
4124 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4128 /* this is a stupid hack because Glib::path_get_dirname() is
4129 * lexical-only, and so passing it /a/b/c/ gives a different
4130 * result than passing it /a/b/c ...
4133 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4134 oldstr = oldstr.substr (0, oldstr.length() - 1);
4137 string base = Glib::path_get_dirname (oldstr);
4139 newstr = Glib::build_filename (base, legal_name);
4141 cerr << "Looking for " << newstr << endl;
4143 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4144 cerr << " exists\n";
4153 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4159 /* this is a stupid hack because Glib::path_get_dirname() is
4160 * lexical-only, and so passing it /a/b/c/ gives a different
4161 * result than passing it /a/b/c ...
4164 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4165 oldstr = oldstr.substr (0, oldstr.length() - 1);
4168 string base = Glib::path_get_dirname (oldstr);
4169 newstr = Glib::build_filename (base, legal_name);
4171 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4173 cerr << "Rename " << oldstr << " => " << newstr << endl;
4174 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4175 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4176 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4180 /* Reset path in "session dirs" */
4185 /* reset primary SessionDirectory object */
4188 (*_session_dir) = newstr;
4193 /* now rename directory below session_dir/interchange */
4195 string old_interchange_dir;
4196 string new_interchange_dir;
4198 /* use newstr here because we renamed the path
4199 * (folder/directory) that used to be oldstr to newstr above
4202 v.push_back (newstr);
4203 v.push_back (interchange_dir_name);
4204 v.push_back (Glib::path_get_basename (oldstr));
4206 old_interchange_dir = Glib::build_filename (v);
4209 v.push_back (newstr);
4210 v.push_back (interchange_dir_name);
4211 v.push_back (legal_name);
4213 new_interchange_dir = Glib::build_filename (v);
4215 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4217 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4218 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4219 old_interchange_dir, new_interchange_dir,
4222 error << string_compose (_("renaming %s as %2 failed (%3)"),
4223 old_interchange_dir, new_interchange_dir,
4232 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4233 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4235 cerr << "Rename " << oldstr << " => " << newstr << endl;
4237 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4238 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4239 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4245 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4247 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4248 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4250 cerr << "Rename " << oldstr << " => " << newstr << endl;
4252 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4253 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4254 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4259 /* remove old name from recent sessions */
4260 remove_recent_sessions (_path);
4263 /* update file source paths */
4265 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4266 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4268 string p = fs->path ();
4269 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4271 SourceFactory::setup_peakfile(i->second, true);
4275 set_snapshot_name (new_name);
4280 /* save state again to get everything just right */
4282 save_state (_current_snapshot_name);
4284 /* add to recent sessions */
4286 store_recent_sessions (new_name, _path);
4292 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4294 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4298 if (!tree.read (xmlpath)) {
4306 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4309 bool found_sr = false;
4310 bool found_data_format = false;
4312 if (get_session_info_from_path (tree, xmlpath)) {
4318 XMLProperty const * prop;
4319 XMLNode const * root (tree.root());
4321 if ((prop = root->property (X_("sample-rate"))) != 0) {
4322 sample_rate = atoi (prop->value());
4326 const XMLNodeList& children (root->children());
4327 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4328 const XMLNode* child = *c;
4329 if (child->name() == "Config") {
4330 const XMLNodeList& options (child->children());
4331 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4332 XMLNode const * option = *oc;
4333 XMLProperty const * name = option->property("name");
4339 if (name->value() == "native-file-data-format") {
4340 XMLProperty const * value = option->property ("value");
4342 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4344 found_data_format = true;
4350 if (found_data_format) {
4355 return !(found_sr && found_data_format); // zero if they are both found
4359 Session::get_snapshot_from_instant (const std::string& session_dir)
4361 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4363 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4368 if (!tree.read (instant_xml_path)) {
4372 XMLProperty const * prop;
4373 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4374 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4375 return prop->value();
4381 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4382 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4385 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4389 SourcePathMap source_path_map;
4391 boost::shared_ptr<AudioFileSource> afs;
4396 Glib::Threads::Mutex::Lock lm (source_lock);
4398 cerr << " total sources = " << sources.size();
4400 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4401 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4407 if (fs->within_session()) {
4411 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4412 source_path_map[fs->path()].push_back (fs);
4414 SeveralFileSources v;
4416 source_path_map.insert (make_pair (fs->path(), v));
4422 cerr << " fsources = " << total << endl;
4424 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4426 /* tell caller where we are */
4428 string old_path = i->first;
4430 callback (n, total, old_path);
4432 cerr << old_path << endl;
4436 switch (i->second.front()->type()) {
4437 case DataType::AUDIO:
4438 new_path = new_audio_source_path_for_embedded (old_path);
4441 case DataType::MIDI:
4442 /* XXX not implemented yet */
4446 if (new_path.empty()) {
4450 cerr << "Move " << old_path << " => " << new_path << endl;
4452 if (!copy_file (old_path, new_path)) {
4453 cerr << "failed !\n";
4457 /* make sure we stop looking in the external
4458 dir/folder. Remember, this is an all-or-nothing
4459 operations, it doesn't merge just some files.
4461 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4463 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4464 (*f)->set_path (new_path);
4469 save_state ("", false, false);
4475 bool accept_all_files (string const &, void *)
4481 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4483 /* 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.
4488 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4490 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4492 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4494 v.push_back (new_session_folder); /* full path */
4495 v.push_back (interchange_dir_name);
4496 v.push_back (new_session_path); /* just one directory/folder */
4497 v.push_back (typedir);
4498 v.push_back (Glib::path_get_basename (old_path));
4500 return Glib::build_filename (v);
4504 Session::save_as (SaveAs& saveas)
4506 vector<string> files;
4507 string current_folder = Glib::path_get_dirname (_path);
4508 string new_folder = legalize_for_path (saveas.new_name);
4509 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4510 int64_t total_bytes = 0;
4514 int32_t internal_file_cnt = 0;
4516 vector<string> do_not_copy_extensions;
4517 do_not_copy_extensions.push_back (statefile_suffix);
4518 do_not_copy_extensions.push_back (pending_suffix);
4519 do_not_copy_extensions.push_back (backup_suffix);
4520 do_not_copy_extensions.push_back (temp_suffix);
4521 do_not_copy_extensions.push_back (history_suffix);
4523 /* get total size */
4525 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4527 /* need to clear this because
4528 * find_files_matching_filter() is cumulative
4533 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4535 all += files.size();
4537 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4539 g_stat ((*i).c_str(), &gsb);
4540 total_bytes += gsb.st_size;
4544 /* save old values so we can switch back if we are not switching to the new session */
4546 string old_path = _path;
4547 string old_name = _name;
4548 string old_snapshot = _current_snapshot_name;
4549 string old_sd = _session_dir->root_path();
4550 vector<string> old_search_path[DataType::num_types];
4551 string old_config_search_path[DataType::num_types];
4553 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4554 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4555 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4556 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4558 /* switch session directory */
4560 (*_session_dir) = to_dir;
4562 /* create new tree */
4564 if (!_session_dir->create()) {
4565 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4570 /* copy all relevant files. Find each location in session_dirs,
4571 * and copy files from there to target.
4574 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4576 /* need to clear this because
4577 * find_files_matching_filter() is cumulative
4582 const size_t prefix_len = (*sd).path.size();
4584 /* Work just on the files within this session dir */
4586 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4588 /* add dir separator to protect against collisions with
4589 * track names (e.g. track named "audiofiles" or
4593 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4594 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4595 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4597 /* copy all the files. Handling is different for media files
4598 than others because of the *silly* subtree we have below the interchange
4599 folder. That really was a bad idea, but I'm not fixing it as part of
4600 implementing ::save_as().
4603 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4605 std::string from = *i;
4608 string filename = Glib::path_get_basename (from);
4609 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4610 if (filename == ".DS_STORE") {
4615 if (from.find (audiofile_dir_string) != string::npos) {
4617 /* audio file: only copy if asked */
4619 if (saveas.include_media && saveas.copy_media) {
4621 string to = make_new_media_path (*i, to_dir, new_folder);
4623 info << "media file copying from " << from << " to " << to << endmsg;
4625 if (!copy_file (from, to)) {
4626 throw Glib::FileError (Glib::FileError::IO_ERROR,
4627 string_compose(_("\ncopying \"%1\" failed !"), from));
4631 /* we found media files inside the session folder */
4633 internal_file_cnt++;
4635 } else if (from.find (midifile_dir_string) != string::npos) {
4637 /* midi file: always copy unless
4638 * creating an empty new session
4641 if (saveas.include_media) {
4643 string to = make_new_media_path (*i, to_dir, new_folder);
4645 info << "media file copying from " << from << " to " << to << endmsg;
4647 if (!copy_file (from, to)) {
4648 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4652 /* we found media files inside the session folder */
4654 internal_file_cnt++;
4656 } else if (from.find (analysis_dir_string) != string::npos) {
4658 /* make sure analysis dir exists in
4659 * new session folder, but we're not
4660 * copying analysis files here, see
4664 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4669 /* normal non-media file. Don't copy state, history, etc.
4672 bool do_copy = true;
4674 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4675 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4676 /* end of filename matches extension, do not copy file */
4682 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4683 /* don't copy peakfiles if
4684 * we're not copying media
4690 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4692 info << "attempting to make directory/folder " << to << endmsg;
4694 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4695 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4698 info << "attempting to copy " << from << " to " << to << endmsg;
4700 if (!copy_file (from, to)) {
4701 throw Glib::FileError (Glib::FileError::IO_ERROR,
4702 string_compose(_("\ncopying \"%1\" failed !"), from));
4707 /* measure file size even if we're not going to copy so that our Progress
4708 signals are correct, since we included these do-not-copy files
4709 in the computation of the total size and file count.
4713 g_stat (from.c_str(), &gsb);
4714 copied += gsb.st_size;
4717 double fraction = (double) copied / total_bytes;
4719 bool keep_going = true;
4721 if (saveas.copy_media) {
4723 /* no need or expectation of this if
4724 * media is not being copied, because
4725 * it will be fast(ish).
4728 /* tell someone "X percent, file M of N"; M is one-based */
4730 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4738 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4744 /* copy optional folders, if any */
4746 string old = plugins_dir ();
4747 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4748 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4749 copy_files (old, newdir);
4752 old = externals_dir ();
4753 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4754 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4755 copy_files (old, newdir);
4758 old = automation_dir ();
4759 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4760 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4761 copy_files (old, newdir);
4764 if (saveas.include_media) {
4766 if (saveas.copy_media) {
4767 #ifndef PLATFORM_WINDOWS
4768 /* There are problems with analysis files on
4769 * Windows, because they used a colon in their
4770 * names as late as 4.0. Colons are not legal
4771 * under Windows even if NTFS allows them.
4773 * This is a tricky problem to solve so for
4774 * just don't copy these files. They will be
4775 * regenerated as-needed anyway, subject to the
4776 * existing issue that the filenames will be
4777 * rejected by Windows, which is a separate
4778 * problem (though related).
4781 /* only needed if we are copying media, since the
4782 * analysis data refers to media data
4785 old = analysis_dir ();
4786 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4787 string newdir = Glib::build_filename (to_dir, "analysis");
4788 copy_files (old, newdir);
4790 #endif /* PLATFORM_WINDOWS */
4796 set_snapshot_name (saveas.new_name);
4797 _name = saveas.new_name;
4799 if (saveas.include_media && !saveas.copy_media) {
4801 /* reset search paths of the new session (which we're pretending to be right now) to
4802 include the original session search path, so we can still find all audio.
4805 if (internal_file_cnt) {
4806 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4807 ensure_search_path_includes (*s, DataType::AUDIO);
4808 cerr << "be sure to include " << *s << " for audio" << endl;
4811 /* we do not do this for MIDI because we copy
4812 all MIDI files if saveas.include_media is
4818 bool was_dirty = dirty ();
4820 save_state ("", false, false, !saveas.include_media);
4821 save_default_options ();
4823 if (saveas.copy_media && saveas.copy_external) {
4824 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4825 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4829 saveas.final_session_folder_name = _path;
4831 store_recent_sessions (_name, _path);
4833 if (!saveas.switch_to) {
4835 /* switch back to the way things were */
4839 set_snapshot_name (old_snapshot);
4841 (*_session_dir) = old_sd;
4847 if (internal_file_cnt) {
4848 /* reset these to their original values */
4849 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4850 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4855 /* prune session dirs, and update disk space statistics
4860 session_dirs.clear ();
4861 session_dirs.push_back (sp);
4862 refresh_disk_space ();
4864 /* ensure that all existing tracks reset their current capture source paths
4866 reset_write_sources (true, true);
4868 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4869 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4872 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4873 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4879 if (fs->within_session()) {
4880 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4881 fs->set_path (newpath);
4886 } catch (Glib::FileError& e) {
4888 saveas.failure_message = e.what();
4890 /* recursively remove all the directories */
4892 remove_directory (to_dir);
4900 saveas.failure_message = _("unknown reason");
4902 /* recursively remove all the directories */
4904 remove_directory (to_dir);