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 #include <sys/param.h>
43 #include <sys/mount.h>
46 #ifdef HAVE_SYS_STATVFS_H
47 #include <sys/statvfs.h>
51 #include "pbd/gstdio_compat.h"
54 #include <glibmm/threads.h>
55 #include <glibmm/fileutils.h>
57 #include <boost/algorithm/string.hpp>
59 #include "midi++/mmc.h"
60 #include "midi++/port.h"
62 #include "evoral/SMF.hpp"
64 #include "pbd/boost_debug.h"
65 #include "pbd/basename.h"
66 #include "pbd/controllable_descriptor.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/playlist_source.h"
101 #include "ardour/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/profile.h"
104 #include "ardour/proxy_controllable.h"
105 #include "ardour/recent_sessions.h"
106 #include "ardour/region_factory.h"
107 #include "ardour/route_group.h"
108 #include "ardour/send.h"
109 #include "ardour/session.h"
110 #include "ardour/session_directory.h"
111 #include "ardour/session_metadata.h"
112 #include "ardour/session_playlists.h"
113 #include "ardour/session_state_utils.h"
114 #include "ardour/silentfilesource.h"
115 #include "ardour/sndfilesource.h"
116 #include "ardour/source_factory.h"
117 #include "ardour/speakers.h"
118 #include "ardour/template_utils.h"
119 #include "ardour/tempo.h"
120 #include "ardour/ticker.h"
121 #include "ardour/user_bundle.h"
123 #include "control_protocol/control_protocol.h"
125 #include "LuaBridge/LuaBridge.h"
131 using namespace ARDOUR;
134 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
137 Session::pre_engine_init (string fullpath)
139 if (fullpath.empty()) {
141 throw failed_constructor();
144 /* discover canonical fullpath */
146 _path = canonical_path(fullpath);
149 if (Profile->get_trx() ) {
150 // Waves TracksLive has a usecase of session replacement with a new one.
151 // We should check session state file (<session_name>.ardour) existance
152 // to determine if the session is new or not
154 string full_session_name = Glib::build_filename( fullpath, _name );
155 full_session_name += statefile_suffix;
157 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
159 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
162 /* finish initialization that can't be done in a normal C++ constructor
166 timerclear (&last_mmc_step);
167 g_atomic_int_set (&processing_prohibited, 0);
168 g_atomic_int_set (&_record_status, Disabled);
169 g_atomic_int_set (&_playback_load, 100);
170 g_atomic_int_set (&_capture_load, 100);
172 _all_route_group->set_active (true, this);
173 interpolation.add_channel_to (0, 0);
175 if (config.get_use_video_sync()) {
176 waiting_for_sync_offset = true;
178 waiting_for_sync_offset = false;
181 last_rr_session_dir = session_dirs.begin();
183 set_history_depth (Config->get_history_depth());
185 /* default: assume simple stereo speaker configuration */
187 _speakers->setup_default_speakers (2);
189 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
190 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
191 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
192 add_controllable (_solo_cut_control);
194 /* These are all static "per-class" signals */
196 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
197 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
198 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
199 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
200 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
202 /* stop IO objects from doing stuff until we're ready for them */
204 Delivery::disable_panners ();
205 IO::disable_connecting ();
209 Session::post_engine_init ()
211 BootMessage (_("Set block size and sample rate"));
213 set_block_size (_engine.samples_per_cycle());
214 set_frame_rate (_engine.sample_rate());
216 BootMessage (_("Using configuration"));
218 _midi_ports = new MidiPortManager;
220 MIDISceneChanger* msc;
222 _scene_changer = msc = new MIDISceneChanger (*this);
223 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
224 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
226 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
227 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
229 setup_midi_machine_control ();
231 if (_butler->start_thread()) {
235 if (start_midi_thread ()) {
239 setup_click_sounds (0);
240 setup_midi_control ();
242 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
243 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
246 /* tempo map requires sample rate knowledge */
249 _tempo_map = new TempoMap (_current_frame_rate);
250 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
252 /* MidiClock requires a tempo map */
254 midi_clock = new MidiClockTicker ();
255 midi_clock->set_session (this);
257 /* crossfades require sample rate knowledge */
259 SndFileSource::setup_standard_crossfades (*this, frame_rate());
260 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
262 AudioDiskstream::allocate_working_buffers();
263 refresh_disk_space ();
265 /* we're finally ready to call set_state() ... all objects have
266 * been created, the engine is running.
270 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
274 // set_state() will call setup_raid_path(), but if it's a new session we need
275 // to call setup_raid_path() here.
276 setup_raid_path (_path);
281 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
282 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
284 Config->map_parameters (ff);
285 config.map_parameters (ft);
286 _butler->map_parameters ();
288 /* Reset all panners */
290 Delivery::reset_panners ();
292 /* this will cause the CPM to instantiate any protocols that are in use
293 * (or mandatory), which will pass it this Session, and then call
294 * set_state() on each instantiated protocol to match stored state.
297 ControlProtocolManager::instance().set_session (this);
299 /* This must be done after the ControlProtocolManager set_session above,
300 as it will set states for ports which the ControlProtocolManager creates.
303 // XXX set state of MIDI::Port's
304 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
306 /* And this must be done after the MIDI::Manager::set_port_states as
307 * it will try to make connections whose details are loaded by set_port_states.
312 /* Let control protocols know that we are now all connected, so they
313 * could start talking to surfaces if they want to.
316 ControlProtocolManager::instance().midi_connectivity_established ();
318 if (_is_new && !no_auto_connect()) {
319 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
320 auto_connect_master_bus ();
323 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
325 /* update latencies */
327 initialize_latencies ();
329 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
330 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
331 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
333 } catch (AudioEngine::PortRegistrationFailure& err) {
334 /* handle this one in a different way than all others, so that its clear what happened */
335 error << err.what() << endmsg;
341 BootMessage (_("Reset Remote Controls"));
343 // send_full_time_code (0);
344 _engine.transport_locate (0);
346 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
347 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
349 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
352 /* initial program change will be delivered later; see ::config_changed() */
354 _state_of_the_state = Clean;
356 Port::set_connecting_blocked (false);
358 DirtyChanged (); /* EMIT SIGNAL */
362 } else if (state_was_pending) {
364 remove_pending_capture_state ();
365 state_was_pending = false;
368 /* Now, finally, we can fill the playback buffers */
370 BootMessage (_("Filling playback buffers"));
372 boost::shared_ptr<RouteList> rl = routes.reader();
373 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
374 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
375 if (trk && !trk->hidden()) {
376 trk->seek (_transport_frame, true);
384 Session::session_loaded ()
388 _state_of_the_state = Clean;
390 DirtyChanged (); /* EMIT SIGNAL */
394 } else if (state_was_pending) {
396 remove_pending_capture_state ();
397 state_was_pending = false;
400 /* Now, finally, we can fill the playback buffers */
402 BootMessage (_("Filling playback buffers"));
403 force_locate (_transport_frame, false);
407 Session::raid_path () const
409 Searchpath raid_search_path;
411 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
412 raid_search_path += (*i).path;
415 return raid_search_path.to_string ();
419 Session::setup_raid_path (string path)
428 session_dirs.clear ();
430 Searchpath search_path(path);
431 Searchpath sound_search_path;
432 Searchpath midi_search_path;
434 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
436 sp.blocks = 0; // not needed
437 session_dirs.push_back (sp);
439 SessionDirectory sdir(sp.path);
441 sound_search_path += sdir.sound_path ();
442 midi_search_path += sdir.midi_path ();
445 // reset the round-robin soundfile path thingie
446 last_rr_session_dir = session_dirs.begin();
450 Session::path_is_within_session (const std::string& path)
452 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
453 if (PBD::path_is_within (i->path, path)) {
461 Session::ensure_subdirs ()
465 dir = session_directory().peak_path();
467 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
468 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
472 dir = session_directory().sound_path();
474 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
475 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
479 dir = session_directory().midi_path();
481 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
482 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
486 dir = session_directory().dead_path();
488 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
489 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
493 dir = session_directory().export_path();
495 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
496 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
500 dir = analysis_dir ();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = plugins_dir ();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = externals_dir ();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 /** @param session_template directory containing session template, or empty.
525 * Caller must not hold process lock.
528 Session::create (const string& session_template, BusProfile* bus_profile)
530 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
535 if (ensure_subdirs ()) {
539 _writable = exists_and_writable (_path);
541 if (!session_template.empty()) {
542 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
544 FILE* in = g_fopen (in_path.c_str(), "rb");
547 /* no need to call legalize_for_path() since the string
548 * in session_template is already a legal path name
550 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
552 FILE* out = g_fopen (out_path.c_str(), "wb");
556 stringstream new_session;
559 size_t charsRead = fread (buf, sizeof(char), 1024, in);
562 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
567 if (charsRead == 0) {
570 new_session.write (buf, charsRead);
574 string file_contents = new_session.str();
575 size_t writeSize = file_contents.length();
576 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
577 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
585 if (!ARDOUR::Profile->get_trx()) {
586 /* Copy plugin state files from template to new session */
587 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
588 copy_recurse (template_plugins, plugins_dir ());
594 error << string_compose (_("Could not open %1 for writing session template"), out_path)
601 error << string_compose (_("Could not open session template %1 for reading"), in_path)
608 if (Profile->get_trx()) {
610 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
611 Remember that this is a brand new session. Sessions
612 loaded from saved state will get this range from the saved state.
615 set_session_range_location (0, 0);
617 /* Initial loop location, from absolute zero, length 10 seconds */
619 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
620 _locations->add (loc, true);
621 set_auto_loop_location (loc);
624 _state_of_the_state = Clean;
626 /* set up Master Out and Control Out if necessary */
631 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
633 // Waves Tracks: always create master bus for Tracks
634 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
635 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
639 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
640 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
643 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
644 r->input()->ensure_io (count, false, this);
645 r->output()->ensure_io (count, false, this);
651 /* prohibit auto-connect to master, because there isn't one */
652 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
656 add_routes (rl, false, false, false);
659 // Waves Tracks: Skip this. Always use autoconnection for Tracks
660 if (!ARDOUR::Profile->get_trx()) {
662 /* this allows the user to override settings with an environment variable.
665 if (no_auto_connect()) {
666 bus_profile->input_ac = AutoConnectOption (0);
667 bus_profile->output_ac = AutoConnectOption (0);
670 Config->set_input_auto_connect (bus_profile->input_ac);
671 Config->set_output_auto_connect (bus_profile->output_ac);
675 if (Config->get_use_monitor_bus() && bus_profile) {
676 add_monitor_section ();
683 Session::maybe_write_autosave()
685 if (dirty() && record_status() != Recording) {
686 save_state("", true);
691 Session::remove_pending_capture_state ()
693 std::string pending_state_file_path(_session_dir->root_path());
695 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
697 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
699 if (g_remove (pending_state_file_path.c_str()) != 0) {
700 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
701 pending_state_file_path, g_strerror (errno)) << endmsg;
705 /** Rename a state file.
706 * @param old_name Old snapshot name.
707 * @param new_name New snapshot name.
710 Session::rename_state (string old_name, string new_name)
712 if (old_name == _current_snapshot_name || old_name == _name) {
713 /* refuse to rename the current snapshot or the "main" one */
717 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
718 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
720 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
721 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
723 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
724 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
725 old_name, new_name, g_strerror(errno)) << endmsg;
729 /** Remove a state file.
730 * @param snapshot_name Snapshot name.
733 Session::remove_state (string snapshot_name)
735 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
736 // refuse to remove the current snapshot or the "main" one
740 std::string xml_path(_session_dir->root_path());
742 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
744 if (!create_backup_file (xml_path)) {
745 // don't remove it if a backup can't be made
746 // create_backup_file will log the error.
751 if (g_remove (xml_path.c_str()) != 0) {
752 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
753 xml_path, g_strerror (errno)) << endmsg;
757 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
759 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
762 std::string xml_path(_session_dir->root_path());
764 /* prevent concurrent saves from different threads */
766 Glib::Threads::Mutex::Lock lm (save_state_lock);
768 if (!_writable || (_state_of_the_state & CannotSave)) {
772 if (g_atomic_int_get(&_suspend_save)) {
776 _save_queued = false;
778 if (!_engine.connected ()) {
779 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
786 const int64_t save_start_time = g_get_monotonic_time();
789 /* tell sources we're saving first, in case they write out to a new file
790 * which should be saved with the state rather than the old one */
791 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
793 i->second->session_saved();
794 } catch (Evoral::SMF::FileError& e) {
795 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
799 SessionSaveUnderway (); /* EMIT SIGNAL */
801 bool mark_as_clean = true;
803 if (!snapshot_name.empty() && !switch_to_snapshot) {
804 mark_as_clean = false;
808 mark_as_clean = false;
809 tree.set_root (&get_template());
811 tree.set_root (&get_state());
814 if (snapshot_name.empty()) {
815 snapshot_name = _current_snapshot_name;
816 } else if (switch_to_snapshot) {
817 set_snapshot_name (snapshot_name);
820 assert (!snapshot_name.empty());
824 /* proper save: use statefile_suffix (.ardour in English) */
826 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
828 /* make a backup copy of the old file */
830 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
831 // create_backup_file will log the error
837 /* pending save: use pending_suffix (.pending in English) */
838 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
841 std::string tmp_path(_session_dir->root_path());
842 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
844 cerr << "actually writing state to " << tmp_path << endl;
846 if (!tree.write (tmp_path)) {
847 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
848 if (g_remove (tmp_path.c_str()) != 0) {
849 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
850 tmp_path, g_strerror (errno)) << endmsg;
856 cerr << "renaming state to " << xml_path << endl;
858 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
859 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
860 tmp_path, xml_path, g_strerror(errno)) << endmsg;
861 if (g_remove (tmp_path.c_str()) != 0) {
862 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
863 tmp_path, g_strerror (errno)) << endmsg;
871 save_history (snapshot_name);
874 bool was_dirty = dirty();
876 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
879 DirtyChanged (); /* EMIT SIGNAL */
883 StateSaved (snapshot_name); /* EMIT SIGNAL */
887 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
888 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
894 Session::restore_state (string snapshot_name)
896 if (load_state (snapshot_name) == 0) {
897 set_state (*state_tree->root(), Stateful::loading_state_version);
904 Session::load_state (string snapshot_name)
909 state_was_pending = false;
911 /* check for leftover pending state from a crashed capture attempt */
913 std::string xmlpath(_session_dir->root_path());
914 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
916 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
918 /* there is pending state from a crashed capture attempt */
920 boost::optional<int> r = AskAboutPendingState();
921 if (r.get_value_or (1)) {
922 state_was_pending = true;
926 if (!state_was_pending) {
927 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
930 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
931 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
932 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
933 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
938 state_tree = new XMLTree;
942 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
944 if (!state_tree->read (xmlpath)) {
945 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
951 XMLNode& root (*state_tree->root());
953 if (root.name() != X_("Session")) {
954 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
960 const XMLProperty* prop;
962 if ((prop = root.property ("version")) == 0) {
963 /* no version implies very old version of Ardour */
964 Stateful::loading_state_version = 1000;
966 if (prop->value().find ('.') != string::npos) {
967 /* old school version format */
968 if (prop->value()[0] == '2') {
969 Stateful::loading_state_version = 2000;
971 Stateful::loading_state_version = 3000;
974 Stateful::loading_state_version = atoi (prop->value());
978 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
980 std::string backup_path(_session_dir->root_path());
981 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
982 backup_path = Glib::build_filename (backup_path, backup_filename);
984 // only create a backup for a given statefile version once
986 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
988 VersionMismatch (xmlpath, backup_path);
990 if (!copy_file (xmlpath, backup_path)) {;
996 save_snapshot_name (snapshot_name);
1002 Session::load_options (const XMLNode& node)
1004 LocaleGuard lg (X_("C"));
1005 config.set_variables (node);
1010 Session::save_default_options ()
1012 return config.save_state();
1016 Session::get_state()
1022 Session::get_template()
1024 /* if we don't disable rec-enable, diskstreams
1025 will believe they need to store their capture
1026 sources in their state node.
1029 disable_record (false);
1031 return state(false);
1035 Session::state (bool full_state)
1037 XMLNode* node = new XMLNode("Session");
1041 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1042 node->add_property("version", buf);
1044 /* store configuration settings */
1048 node->add_property ("name", _name);
1049 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1050 node->add_property ("sample-rate", buf);
1052 if (session_dirs.size() > 1) {
1056 vector<space_and_path>::iterator i = session_dirs.begin();
1057 vector<space_and_path>::iterator next;
1059 ++i; /* skip the first one */
1063 while (i != session_dirs.end()) {
1067 if (next != session_dirs.end()) {
1068 p += G_SEARCHPATH_SEPARATOR;
1077 child = node->add_child ("Path");
1078 child->add_content (p);
1082 /* save the ID counter */
1084 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1085 node->add_property ("id-counter", buf);
1087 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1088 node->add_property ("name-counter", buf);
1090 /* save the event ID counter */
1092 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1093 node->add_property ("event-counter", buf);
1095 /* various options */
1097 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1098 if (!midi_port_nodes.empty()) {
1099 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1100 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1101 midi_port_stuff->add_child_nocopy (**n);
1103 node->add_child_nocopy (*midi_port_stuff);
1106 node->add_child_nocopy (config.get_variables ());
1108 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1110 child = node->add_child ("Sources");
1113 Glib::Threads::Mutex::Lock sl (source_lock);
1115 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1117 /* Don't save information about non-file Sources, or
1118 * about non-destructive file sources that are empty
1119 * and unused by any regions.
1122 boost::shared_ptr<FileSource> fs;
1124 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1126 if (!fs->destructive()) {
1127 if (fs->empty() && !fs->used()) {
1132 child->add_child_nocopy (siter->second->get_state());
1137 child = node->add_child ("Regions");
1140 Glib::Threads::Mutex::Lock rl (region_lock);
1141 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1142 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1143 boost::shared_ptr<Region> r = i->second;
1144 /* only store regions not attached to playlists */
1145 if (r->playlist() == 0) {
1146 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1147 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1149 child->add_child_nocopy (r->get_state ());
1154 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1156 if (!cassocs.empty()) {
1157 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1159 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1161 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1162 i->first->id().print (buf, sizeof (buf));
1163 can->add_property (X_("copy"), buf);
1164 i->second->id().print (buf, sizeof (buf));
1165 can->add_property (X_("original"), buf);
1166 ca->add_child_nocopy (*can);
1176 node->add_child_nocopy (_locations->get_state());
1179 Locations loc (*this);
1180 // for a template, just create a new Locations, populate it
1181 // with the default start and end, and get the state for that.
1182 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1183 range->set (max_framepos, 0);
1185 XMLNode& locations_state = loc.get_state();
1187 if (ARDOUR::Profile->get_trx() && _locations) {
1188 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1189 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1190 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1191 locations_state.add_child_nocopy ((*i)->get_state ());
1195 node->add_child_nocopy (locations_state);
1198 child = node->add_child ("Bundles");
1200 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1201 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1202 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1204 child->add_child_nocopy (b->get_state());
1209 child = node->add_child ("Routes");
1211 boost::shared_ptr<RouteList> r = routes.reader ();
1213 RoutePublicOrderSorter cmp;
1214 RouteList public_order (*r);
1215 public_order.sort (cmp);
1217 /* the sort should have put control outs first */
1220 assert (_monitor_out == public_order.front());
1223 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1224 if (!(*i)->is_auditioner()) {
1226 child->add_child_nocopy ((*i)->get_state());
1228 child->add_child_nocopy ((*i)->get_template());
1234 playlists->add_state (node, full_state);
1236 child = node->add_child ("RouteGroups");
1237 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1238 child->add_child_nocopy ((*i)->get_state());
1242 XMLNode* gain_child = node->add_child ("Click");
1243 gain_child->add_child_nocopy (_click_io->state (full_state));
1244 gain_child->add_child_nocopy (_click_gain->state (full_state));
1248 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1249 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1253 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1254 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1257 node->add_child_nocopy (_speakers->get_state());
1258 node->add_child_nocopy (_tempo_map->get_state());
1259 node->add_child_nocopy (get_control_protocol_state());
1262 node->add_child_copy (*_extra_xml);
1266 Glib::Threads::Mutex::Lock lm (lua_lock);
1269 luabridge::LuaRef savedstate ((*_lua_save)());
1270 saved = savedstate.cast<std::string>();
1272 lua.collect_garbage ();
1275 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1276 std::string b64s (b64);
1279 XMLNode* script_node = new XMLNode (X_("Script"));
1280 script_node->add_property (X_("lua"), LUA_VERSION);
1281 script_node->add_content (b64s);
1282 node->add_child_nocopy (*script_node);
1289 Session::get_control_protocol_state ()
1291 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1292 return cpm.get_state();
1296 Session::set_state (const XMLNode& node, int version)
1300 const XMLProperty* prop;
1303 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1305 if (node.name() != X_("Session")) {
1306 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1310 if ((prop = node.property ("name")) != 0) {
1311 _name = prop->value ();
1314 if ((prop = node.property (X_("sample-rate"))) != 0) {
1316 _nominal_frame_rate = atoi (prop->value());
1318 if (_nominal_frame_rate != _current_frame_rate) {
1319 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1320 if (r.get_value_or (0)) {
1326 setup_raid_path(_session_dir->root_path());
1328 if ((prop = node.property (X_("id-counter"))) != 0) {
1330 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1331 ID::init_counter (x);
1333 /* old sessions used a timebased counter, so fake
1334 the startup ID counter based on a standard
1339 ID::init_counter (now);
1342 if ((prop = node.property (X_("name-counter"))) != 0) {
1343 init_name_id_counter (atoi (prop->value()));
1346 if ((prop = node.property (X_("event-counter"))) != 0) {
1347 Evoral::init_event_id_counter (atoi (prop->value()));
1350 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1351 _midi_ports->set_midi_port_states (child->children());
1354 IO::disable_connecting ();
1356 Stateful::save_extra_xml (node);
1358 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1359 load_options (*child);
1360 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1361 load_options (*child);
1363 error << _("Session: XML state has no options section") << endmsg;
1366 if (version >= 3000) {
1367 if ((child = find_named_node (node, "Metadata")) == 0) {
1368 warning << _("Session: XML state has no metadata section") << endmsg;
1369 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1374 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1375 _speakers->set_state (*child, version);
1378 if ((child = find_named_node (node, "Sources")) == 0) {
1379 error << _("Session: XML state has no sources section") << endmsg;
1381 } else if (load_sources (*child)) {
1385 if ((child = find_named_node (node, "TempoMap")) == 0) {
1386 error << _("Session: XML state has no Tempo Map section") << endmsg;
1388 } else if (_tempo_map->set_state (*child, version)) {
1392 if ((child = find_named_node (node, "Locations")) == 0) {
1393 error << _("Session: XML state has no locations section") << endmsg;
1395 } else if (_locations->set_state (*child, version)) {
1399 locations_changed ();
1401 if (_session_range_location) {
1402 AudioFileSource::set_header_position_offset (_session_range_location->start());
1405 if ((child = find_named_node (node, "Regions")) == 0) {
1406 error << _("Session: XML state has no Regions section") << endmsg;
1408 } else if (load_regions (*child)) {
1412 if ((child = find_named_node (node, "Playlists")) == 0) {
1413 error << _("Session: XML state has no playlists section") << endmsg;
1415 } else if (playlists->load (*this, *child)) {
1419 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1421 } else if (playlists->load_unused (*this, *child)) {
1425 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1426 if (load_compounds (*child)) {
1431 if (version >= 3000) {
1432 if ((child = find_named_node (node, "Bundles")) == 0) {
1433 warning << _("Session: XML state has no bundles section") << endmsg;
1436 /* We can't load Bundles yet as they need to be able
1437 to convert from port names to Port objects, which can't happen until
1439 _bundle_xml_node = new XMLNode (*child);
1443 if (version < 3000) {
1444 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1445 error << _("Session: XML state has no diskstreams section") << endmsg;
1447 } else if (load_diskstreams_2X (*child, version)) {
1452 if ((child = find_named_node (node, "Routes")) == 0) {
1453 error << _("Session: XML state has no routes section") << endmsg;
1455 } else if (load_routes (*child, version)) {
1459 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1460 _diskstreams_2X.clear ();
1462 if (version >= 3000) {
1464 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1465 error << _("Session: XML state has no route groups section") << endmsg;
1467 } else if (load_route_groups (*child, version)) {
1471 } else if (version < 3000) {
1473 if ((child = find_named_node (node, "EditGroups")) == 0) {
1474 error << _("Session: XML state has no edit groups section") << endmsg;
1476 } else if (load_route_groups (*child, version)) {
1480 if ((child = find_named_node (node, "MixGroups")) == 0) {
1481 error << _("Session: XML state has no mix groups section") << endmsg;
1483 } else if (load_route_groups (*child, version)) {
1488 if ((child = find_named_node (node, "Click")) == 0) {
1489 warning << _("Session: XML state has no click section") << endmsg;
1490 } else if (_click_io) {
1491 setup_click_state (&node);
1494 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1495 ControlProtocolManager::instance().set_state (*child, version);
1498 if ((child = find_named_node (node, "Script"))) {
1499 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1500 if (!(*n)->is_content ()) { continue; }
1502 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1504 Glib::Threads::Mutex::Lock lm (lua_lock);
1505 (*_lua_load)(std::string ((const char*)buf, size));
1506 } catch (luabridge::LuaException const& e) {
1507 cerr << "LuaException:" << e.what () << endl;
1513 update_route_record_state ();
1515 /* here beginneth the second phase ... */
1516 set_snapshot_name (_current_snapshot_name);
1518 StateReady (); /* EMIT SIGNAL */
1531 Session::load_routes (const XMLNode& node, int version)
1534 XMLNodeConstIterator niter;
1535 RouteList new_routes;
1537 nlist = node.children();
1541 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1543 boost::shared_ptr<Route> route;
1544 if (version < 3000) {
1545 route = XMLRouteFactory_2X (**niter, version);
1547 route = XMLRouteFactory (**niter, version);
1551 error << _("Session: cannot create Route from XML description.") << endmsg;
1555 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1557 new_routes.push_back (route);
1560 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1562 add_routes (new_routes, false, false, false);
1564 BootMessage (_("Finished adding tracks/busses"));
1569 boost::shared_ptr<Route>
1570 Session::XMLRouteFactory (const XMLNode& node, int version)
1572 boost::shared_ptr<Route> ret;
1574 if (node.name() != "Route") {
1578 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1580 DataType type = DataType::AUDIO;
1581 const XMLProperty* prop = node.property("default-type");
1584 type = DataType (prop->value());
1587 assert (type != DataType::NIL);
1591 boost::shared_ptr<Track> track;
1593 if (type == DataType::AUDIO) {
1594 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1596 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1599 if (track->init()) {
1603 if (track->set_state (node, version)) {
1607 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1608 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1613 enum Route::Flag flags = Route::Flag(0);
1614 const XMLProperty* prop = node.property("flags");
1616 flags = Route::Flag (string_2_enum (prop->value(), flags));
1619 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1621 if (r->init () == 0 && r->set_state (node, version) == 0) {
1622 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1623 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1632 boost::shared_ptr<Route>
1633 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1635 boost::shared_ptr<Route> ret;
1637 if (node.name() != "Route") {
1641 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1643 ds_prop = node.property (X_("diskstream"));
1646 DataType type = DataType::AUDIO;
1647 const XMLProperty* prop = node.property("default-type");
1650 type = DataType (prop->value());
1653 assert (type != DataType::NIL);
1657 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1658 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1662 if (i == _diskstreams_2X.end()) {
1663 error << _("Could not find diskstream for route") << endmsg;
1664 return boost::shared_ptr<Route> ();
1667 boost::shared_ptr<Track> track;
1669 if (type == DataType::AUDIO) {
1670 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1672 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1675 if (track->init()) {
1679 if (track->set_state (node, version)) {
1683 track->set_diskstream (*i);
1685 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1686 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1691 enum Route::Flag flags = Route::Flag(0);
1692 const XMLProperty* prop = node.property("flags");
1694 flags = Route::Flag (string_2_enum (prop->value(), flags));
1697 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1699 if (r->init () == 0 && r->set_state (node, version) == 0) {
1700 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1701 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1711 Session::load_regions (const XMLNode& node)
1714 XMLNodeConstIterator niter;
1715 boost::shared_ptr<Region> region;
1717 nlist = node.children();
1721 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1722 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1723 error << _("Session: cannot create Region from XML description.");
1724 const XMLProperty *name = (**niter).property("name");
1727 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1738 Session::load_compounds (const XMLNode& node)
1740 XMLNodeList calist = node.children();
1741 XMLNodeConstIterator caiter;
1742 XMLProperty *caprop;
1744 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1745 XMLNode* ca = *caiter;
1749 if ((caprop = ca->property (X_("original"))) == 0) {
1752 orig_id = caprop->value();
1754 if ((caprop = ca->property (X_("copy"))) == 0) {
1757 copy_id = caprop->value();
1759 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1760 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1762 if (!orig || !copy) {
1763 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1769 RegionFactory::add_compound_association (orig, copy);
1776 Session::load_nested_sources (const XMLNode& node)
1779 XMLNodeConstIterator niter;
1781 nlist = node.children();
1783 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1784 if ((*niter)->name() == "Source") {
1786 /* it may already exist, so don't recreate it unnecessarily
1789 XMLProperty* prop = (*niter)->property (X_("id"));
1791 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1795 ID source_id (prop->value());
1797 if (!source_by_id (source_id)) {
1800 SourceFactory::create (*this, **niter, true);
1802 catch (failed_constructor& err) {
1803 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1810 boost::shared_ptr<Region>
1811 Session::XMLRegionFactory (const XMLNode& node, bool full)
1813 const XMLProperty* type = node.property("type");
1817 const XMLNodeList& nlist = node.children();
1819 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1820 XMLNode *child = (*niter);
1821 if (child->name() == "NestedSource") {
1822 load_nested_sources (*child);
1826 if (!type || type->value() == "audio") {
1827 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1828 } else if (type->value() == "midi") {
1829 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1832 } catch (failed_constructor& err) {
1833 return boost::shared_ptr<Region> ();
1836 return boost::shared_ptr<Region> ();
1839 boost::shared_ptr<AudioRegion>
1840 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1842 const XMLProperty* prop;
1843 boost::shared_ptr<Source> source;
1844 boost::shared_ptr<AudioSource> as;
1846 SourceList master_sources;
1847 uint32_t nchans = 1;
1850 if (node.name() != X_("Region")) {
1851 return boost::shared_ptr<AudioRegion>();
1854 if ((prop = node.property (X_("channels"))) != 0) {
1855 nchans = atoi (prop->value().c_str());
1858 if ((prop = node.property ("name")) == 0) {
1859 cerr << "no name for this region\n";
1863 if ((prop = node.property (X_("source-0"))) == 0) {
1864 if ((prop = node.property ("source")) == 0) {
1865 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1866 return boost::shared_ptr<AudioRegion>();
1870 PBD::ID s_id (prop->value());
1872 if ((source = source_by_id (s_id)) == 0) {
1873 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1874 return boost::shared_ptr<AudioRegion>();
1877 as = boost::dynamic_pointer_cast<AudioSource>(source);
1879 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1880 return boost::shared_ptr<AudioRegion>();
1883 sources.push_back (as);
1885 /* pickup other channels */
1887 for (uint32_t n=1; n < nchans; ++n) {
1888 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1889 if ((prop = node.property (buf)) != 0) {
1891 PBD::ID id2 (prop->value());
1893 if ((source = source_by_id (id2)) == 0) {
1894 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1895 return boost::shared_ptr<AudioRegion>();
1898 as = boost::dynamic_pointer_cast<AudioSource>(source);
1900 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1901 return boost::shared_ptr<AudioRegion>();
1903 sources.push_back (as);
1907 for (uint32_t n = 0; n < nchans; ++n) {
1908 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1909 if ((prop = node.property (buf)) != 0) {
1911 PBD::ID id2 (prop->value());
1913 if ((source = source_by_id (id2)) == 0) {
1914 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1915 return boost::shared_ptr<AudioRegion>();
1918 as = boost::dynamic_pointer_cast<AudioSource>(source);
1920 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1921 return boost::shared_ptr<AudioRegion>();
1923 master_sources.push_back (as);
1928 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1930 /* a final detail: this is the one and only place that we know how long missing files are */
1932 if (region->whole_file()) {
1933 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1934 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1936 sfp->set_length (region->length());
1941 if (!master_sources.empty()) {
1942 if (master_sources.size() != nchans) {
1943 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1945 region->set_master_sources (master_sources);
1953 catch (failed_constructor& err) {
1954 return boost::shared_ptr<AudioRegion>();
1958 boost::shared_ptr<MidiRegion>
1959 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1961 const XMLProperty* prop;
1962 boost::shared_ptr<Source> source;
1963 boost::shared_ptr<MidiSource> ms;
1966 if (node.name() != X_("Region")) {
1967 return boost::shared_ptr<MidiRegion>();
1970 if ((prop = node.property ("name")) == 0) {
1971 cerr << "no name for this region\n";
1975 if ((prop = node.property (X_("source-0"))) == 0) {
1976 if ((prop = node.property ("source")) == 0) {
1977 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1978 return boost::shared_ptr<MidiRegion>();
1982 PBD::ID s_id (prop->value());
1984 if ((source = source_by_id (s_id)) == 0) {
1985 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1986 return boost::shared_ptr<MidiRegion>();
1989 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1991 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1992 return boost::shared_ptr<MidiRegion>();
1995 sources.push_back (ms);
1998 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1999 /* a final detail: this is the one and only place that we know how long missing files are */
2001 if (region->whole_file()) {
2002 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2003 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2005 sfp->set_length (region->length());
2013 catch (failed_constructor& err) {
2014 return boost::shared_ptr<MidiRegion>();
2019 Session::get_sources_as_xml ()
2022 XMLNode* node = new XMLNode (X_("Sources"));
2023 Glib::Threads::Mutex::Lock lm (source_lock);
2025 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2026 node->add_child_nocopy (i->second->get_state());
2033 Session::reset_write_sources (bool mark_write_complete, bool force)
2035 boost::shared_ptr<RouteList> rl = routes.reader();
2036 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2037 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2039 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2040 tr->reset_write_sources(mark_write_complete, force);
2041 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2047 Session::load_sources (const XMLNode& node)
2050 XMLNodeConstIterator niter;
2051 boost::shared_ptr<Source> source; /* don't need this but it stops some
2052 * versions of gcc complaining about
2053 * discarded return values.
2056 nlist = node.children();
2060 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2063 if ((source = XMLSourceFactory (**niter)) == 0) {
2064 error << _("Session: cannot create Source from XML description.") << endmsg;
2067 } catch (MissingSource& err) {
2071 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2072 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2073 PROGRAM_NAME) << endmsg;
2077 if (!no_questions_about_missing_files) {
2078 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2083 switch (user_choice) {
2085 /* user added a new search location, so try again */
2090 /* user asked to quit the entire session load
2095 no_questions_about_missing_files = true;
2099 no_questions_about_missing_files = true;
2106 case DataType::AUDIO:
2107 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2110 case DataType::MIDI:
2111 /* The MIDI file is actually missing so
2112 * just create a new one in the same
2113 * location. Do not announce its
2117 if (!Glib::path_is_absolute (err.path)) {
2118 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2120 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2125 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2126 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2127 /* reset ID to match the missing one */
2128 source->set_id (**niter);
2129 /* Now we can announce it */
2130 SourceFactory::SourceCreated (source);
2141 boost::shared_ptr<Source>
2142 Session::XMLSourceFactory (const XMLNode& node)
2144 if (node.name() != "Source") {
2145 return boost::shared_ptr<Source>();
2149 /* note: do peak building in another thread when loading session state */
2150 return SourceFactory::create (*this, node, true);
2153 catch (failed_constructor& err) {
2154 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2155 return boost::shared_ptr<Source>();
2160 Session::save_template (string template_name, bool replace_existing)
2162 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2166 bool absolute_path = Glib::path_is_absolute (template_name);
2168 /* directory to put the template in */
2169 std::string template_dir_path;
2171 if (!absolute_path) {
2172 std::string user_template_dir(user_template_directory());
2174 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2175 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2176 user_template_dir, g_strerror (errno)) << endmsg;
2180 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2182 template_dir_path = template_name;
2185 if (!ARDOUR::Profile->get_trx()) {
2186 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2187 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2188 template_dir_path) << endmsg;
2192 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2193 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2194 template_dir_path, g_strerror (errno)) << endmsg;
2200 std::string template_file_path;
2202 if (ARDOUR::Profile->get_trx()) {
2203 template_file_path = template_name;
2205 if (absolute_path) {
2206 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2208 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2212 SessionSaveUnderway (); /* EMIT SIGNAL */
2217 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2218 tree.set_root (&get_template());
2221 if (!tree.write (template_file_path)) {
2222 error << _("template not saved") << endmsg;
2226 store_recent_templates (template_file_path);
2232 Session::refresh_disk_space ()
2234 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2236 Glib::Threads::Mutex::Lock lm (space_lock);
2238 /* get freespace on every FS that is part of the session path */
2240 _total_free_4k_blocks = 0;
2241 _total_free_4k_blocks_uncertain = false;
2243 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2245 struct statfs statfsbuf;
2246 statfs (i->path.c_str(), &statfsbuf);
2248 double const scale = statfsbuf.f_bsize / 4096.0;
2250 /* See if this filesystem is read-only */
2251 struct statvfs statvfsbuf;
2252 statvfs (i->path.c_str(), &statvfsbuf);
2254 /* f_bavail can be 0 if it is undefined for whatever
2255 filesystem we are looking at; Samba shares mounted
2256 via GVFS are an example of this.
2258 if (statfsbuf.f_bavail == 0) {
2259 /* block count unknown */
2261 i->blocks_unknown = true;
2262 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2263 /* read-only filesystem */
2265 i->blocks_unknown = false;
2267 /* read/write filesystem with known space */
2268 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2269 i->blocks_unknown = false;
2272 _total_free_4k_blocks += i->blocks;
2273 if (i->blocks_unknown) {
2274 _total_free_4k_blocks_uncertain = true;
2277 #elif defined PLATFORM_WINDOWS
2278 vector<string> scanned_volumes;
2279 vector<string>::iterator j;
2280 vector<space_and_path>::iterator i;
2281 DWORD nSectorsPerCluster, nBytesPerSector,
2282 nFreeClusters, nTotalClusters;
2286 _total_free_4k_blocks = 0;
2288 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2289 strncpy (disk_drive, (*i).path.c_str(), 3);
2293 volume_found = false;
2294 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2296 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2297 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2298 i->blocks = (uint32_t)(nFreeBytes / 4096);
2300 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2301 if (0 == j->compare(disk_drive)) {
2302 volume_found = true;
2307 if (!volume_found) {
2308 scanned_volumes.push_back(disk_drive);
2309 _total_free_4k_blocks += i->blocks;
2314 if (0 == _total_free_4k_blocks) {
2315 strncpy (disk_drive, path().c_str(), 3);
2318 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2320 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2321 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2322 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2329 Session::get_best_session_directory_for_new_audio ()
2331 vector<space_and_path>::iterator i;
2332 string result = _session_dir->root_path();
2334 /* handle common case without system calls */
2336 if (session_dirs.size() == 1) {
2340 /* OK, here's the algorithm we're following here:
2342 We want to select which directory to use for
2343 the next file source to be created. Ideally,
2344 we'd like to use a round-robin process so as to
2345 get maximum performance benefits from splitting
2346 the files across multiple disks.
2348 However, in situations without much diskspace, an
2349 RR approach may end up filling up a filesystem
2350 with new files while others still have space.
2351 Its therefore important to pay some attention to
2352 the freespace in the filesystem holding each
2353 directory as well. However, if we did that by
2354 itself, we'd keep creating new files in the file
2355 system with the most space until it was as full
2356 as all others, thus negating any performance
2357 benefits of this RAID-1 like approach.
2359 So, we use a user-configurable space threshold. If
2360 there are at least 2 filesystems with more than this
2361 much space available, we use RR selection between them.
2362 If not, then we pick the filesystem with the most space.
2364 This gets a good balance between the two
2368 refresh_disk_space ();
2370 int free_enough = 0;
2372 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2373 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2378 if (free_enough >= 2) {
2379 /* use RR selection process, ensuring that the one
2383 i = last_rr_session_dir;
2386 if (++i == session_dirs.end()) {
2387 i = session_dirs.begin();
2390 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2391 SessionDirectory sdir(i->path);
2392 if (sdir.create ()) {
2394 last_rr_session_dir = i;
2399 } while (i != last_rr_session_dir);
2403 /* pick FS with the most freespace (and that
2404 seems to actually work ...)
2407 vector<space_and_path> sorted;
2408 space_and_path_ascending_cmp cmp;
2410 sorted = session_dirs;
2411 sort (sorted.begin(), sorted.end(), cmp);
2413 for (i = sorted.begin(); i != sorted.end(); ++i) {
2414 SessionDirectory sdir(i->path);
2415 if (sdir.create ()) {
2417 last_rr_session_dir = i;
2427 Session::automation_dir () const
2429 return Glib::build_filename (_path, automation_dir_name);
2433 Session::analysis_dir () const
2435 return Glib::build_filename (_path, analysis_dir_name);
2439 Session::plugins_dir () const
2441 return Glib::build_filename (_path, plugins_dir_name);
2445 Session::externals_dir () const
2447 return Glib::build_filename (_path, externals_dir_name);
2451 Session::load_bundles (XMLNode const & node)
2453 XMLNodeList nlist = node.children();
2454 XMLNodeConstIterator niter;
2458 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2459 if ((*niter)->name() == "InputBundle") {
2460 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2461 } else if ((*niter)->name() == "OutputBundle") {
2462 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2464 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2473 Session::load_route_groups (const XMLNode& node, int version)
2475 XMLNodeList nlist = node.children();
2476 XMLNodeConstIterator niter;
2480 if (version >= 3000) {
2482 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2483 if ((*niter)->name() == "RouteGroup") {
2484 RouteGroup* rg = new RouteGroup (*this, "");
2485 add_route_group (rg);
2486 rg->set_state (**niter, version);
2490 } else if (version < 3000) {
2492 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2493 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2494 RouteGroup* rg = new RouteGroup (*this, "");
2495 add_route_group (rg);
2496 rg->set_state (**niter, version);
2505 state_file_filter (const string &str, void* /*arg*/)
2507 return (str.length() > strlen(statefile_suffix) &&
2508 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2512 remove_end(string state)
2514 string statename(state);
2516 string::size_type start,end;
2517 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2518 statename = statename.substr (start+1);
2521 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2522 end = statename.length();
2525 return string(statename.substr (0, end));
2529 Session::possible_states (string path)
2531 vector<string> states;
2532 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2534 transform(states.begin(), states.end(), states.begin(), remove_end);
2536 sort (states.begin(), states.end());
2542 Session::possible_states () const
2544 return possible_states(_path);
2548 Session::add_route_group (RouteGroup* g)
2550 _route_groups.push_back (g);
2551 route_group_added (g); /* EMIT SIGNAL */
2553 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2554 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2555 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2561 Session::remove_route_group (RouteGroup& rg)
2563 list<RouteGroup*>::iterator i;
2565 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2566 _route_groups.erase (i);
2569 route_group_removed (); /* EMIT SIGNAL */
2573 /** Set a new order for our route groups, without adding or removing any.
2574 * @param groups Route group list in the new order.
2577 Session::reorder_route_groups (list<RouteGroup*> groups)
2579 _route_groups = groups;
2581 route_groups_reordered (); /* EMIT SIGNAL */
2587 Session::route_group_by_name (string name)
2589 list<RouteGroup *>::iterator i;
2591 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2592 if ((*i)->name() == name) {
2600 Session::all_route_group() const
2602 return *_all_route_group;
2606 Session::add_commands (vector<Command*> const & cmds)
2608 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2614 Session::add_command (Command* const cmd)
2616 assert (_current_trans);
2617 DEBUG_UNDO_HISTORY (
2618 string_compose ("Current Undo Transaction %1, adding command: %2",
2619 _current_trans->name (),
2621 _current_trans->add_command (cmd);
2624 PBD::StatefulDiffCommand*
2625 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2627 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2633 Session::begin_reversible_command (const string& name)
2635 begin_reversible_command (g_quark_from_string (name.c_str ()));
2638 /** Begin a reversible command using a GQuark to identify it.
2639 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2640 * but there must be as many begin...()s as there are commit...()s.
2643 Session::begin_reversible_command (GQuark q)
2645 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2646 to hold all the commands that are committed. This keeps the order of
2647 commands correct in the history.
2650 if (_current_trans == 0) {
2651 DEBUG_UNDO_HISTORY (string_compose (
2652 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2654 /* start a new transaction */
2655 assert (_current_trans_quarks.empty ());
2656 _current_trans = new UndoTransaction();
2657 _current_trans->set_name (g_quark_to_string (q));
2659 DEBUG_UNDO_HISTORY (
2660 string_compose ("Begin Reversible Command, current transaction: %1",
2661 _current_trans->name ()));
2664 _current_trans_quarks.push_front (q);
2668 Session::abort_reversible_command ()
2670 if (_current_trans != 0) {
2671 DEBUG_UNDO_HISTORY (
2672 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2673 _current_trans->clear();
2674 delete _current_trans;
2676 _current_trans_quarks.clear();
2681 Session::commit_reversible_command (Command *cmd)
2683 assert (_current_trans);
2684 assert (!_current_trans_quarks.empty ());
2689 DEBUG_UNDO_HISTORY (
2690 string_compose ("Current Undo Transaction %1, adding command: %2",
2691 _current_trans->name (),
2693 _current_trans->add_command (cmd);
2696 DEBUG_UNDO_HISTORY (
2697 string_compose ("Commit Reversible Command, current transaction: %1",
2698 _current_trans->name ()));
2700 _current_trans_quarks.pop_front ();
2702 if (!_current_trans_quarks.empty ()) {
2703 DEBUG_UNDO_HISTORY (
2704 string_compose ("Commit Reversible Command, transaction is not "
2705 "top-level, current transaction: %1",
2706 _current_trans->name ()));
2707 /* the transaction we're committing is not the top-level one */
2711 if (_current_trans->empty()) {
2712 /* no commands were added to the transaction, so just get rid of it */
2713 DEBUG_UNDO_HISTORY (
2714 string_compose ("Commit Reversible Command, No commands were "
2715 "added to current transaction: %1",
2716 _current_trans->name ()));
2717 delete _current_trans;
2722 gettimeofday (&now, 0);
2723 _current_trans->set_timestamp (now);
2725 _history.add (_current_trans);
2730 accept_all_audio_files (const string& path, void* /*arg*/)
2732 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2736 if (!AudioFileSource::safe_audio_file_extension (path)) {
2744 accept_all_midi_files (const string& path, void* /*arg*/)
2746 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2750 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2751 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2752 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2756 accept_all_state_files (const string& path, void* /*arg*/)
2758 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2762 std::string const statefile_ext (statefile_suffix);
2763 if (path.length() >= statefile_ext.length()) {
2764 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2771 Session::find_all_sources (string path, set<string>& result)
2776 if (!tree.read (path)) {
2780 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2785 XMLNodeConstIterator niter;
2787 nlist = node->children();
2791 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2795 if ((prop = (*niter)->property (X_("type"))) == 0) {
2799 DataType type (prop->value());
2801 if ((prop = (*niter)->property (X_("name"))) == 0) {
2805 if (Glib::path_is_absolute (prop->value())) {
2806 /* external file, ignore */
2814 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2815 result.insert (found_path);
2823 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2825 vector<string> state_files;
2827 string this_snapshot_path;
2833 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2834 ripped = ripped.substr (0, ripped.length() - 1);
2837 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2839 if (state_files.empty()) {
2844 this_snapshot_path = _path;
2845 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2846 this_snapshot_path += statefile_suffix;
2848 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2850 if (exclude_this_snapshot && *i == this_snapshot_path) {
2854 if (find_all_sources (*i, result) < 0) {
2862 struct RegionCounter {
2863 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2864 AudioSourceList::iterator iter;
2865 boost::shared_ptr<Region> region;
2868 RegionCounter() : count (0) {}
2872 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2874 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2875 return r.get_value_or (1);
2879 Session::cleanup_regions ()
2881 bool removed = false;
2882 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2884 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2886 uint32_t used = playlists->region_use_count (i->second);
2888 if (used == 0 && !i->second->automatic ()) {
2889 boost::weak_ptr<Region> w = i->second;
2892 RegionFactory::map_remove (w);
2899 // re-check to remove parent references of compound regions
2900 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2901 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2905 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2906 if (0 == playlists->region_use_count (i->second)) {
2907 boost::weak_ptr<Region> w = i->second;
2909 RegionFactory::map_remove (w);
2916 /* dump the history list */
2923 Session::can_cleanup_peakfiles () const
2925 if (deletion_in_progress()) {
2928 if (!_writable || (_state_of_the_state & CannotSave)) {
2929 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2932 if (record_status() == Recording) {
2933 error << _("Cannot cleanup peak-files while recording") << endmsg;
2940 Session::cleanup_peakfiles ()
2942 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2947 assert (can_cleanup_peakfiles ());
2948 assert (!peaks_cleanup_in_progres());
2950 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2952 int timeout = 5000; // 5 seconds
2953 while (!SourceFactory::files_with_peaks.empty()) {
2954 Glib::usleep (1000);
2955 if (--timeout < 0) {
2956 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2957 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2962 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2963 boost::shared_ptr<AudioSource> as;
2964 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2965 as->close_peakfile();
2969 PBD::clear_directory (session_directory().peak_path());
2971 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2973 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2974 boost::shared_ptr<AudioSource> as;
2975 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2976 SourceFactory::setup_peakfile(as, true);
2983 Session::cleanup_sources (CleanupReport& rep)
2985 // FIXME: needs adaptation to midi
2987 vector<boost::shared_ptr<Source> > dead_sources;
2990 vector<string> candidates;
2991 vector<string> unused;
2992 set<string> all_sources;
3001 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3003 /* this is mostly for windows which doesn't allow file
3004 * renaming if the file is in use. But we don't special
3005 * case it because we need to know if this causes
3006 * problems, and the easiest way to notice that is to
3007 * keep it in place for all platforms.
3010 request_stop (false);
3012 _butler->wait_until_finished ();
3014 /* consider deleting all unused playlists */
3016 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3021 /* sync the "all regions" property of each playlist with its current state
3024 playlists->sync_all_regions_with_regions ();
3026 /* find all un-used sources */
3031 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3033 SourceMap::iterator tmp;
3038 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3042 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3043 dead_sources.push_back (i->second);
3044 i->second->drop_references ();
3050 /* build a list of all the possible audio directories for the session */
3052 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3053 SessionDirectory sdir ((*i).path);
3054 asp += sdir.sound_path();
3056 audio_path += asp.to_string();
3059 /* build a list of all the possible midi directories for the session */
3061 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3062 SessionDirectory sdir ((*i).path);
3063 msp += sdir.midi_path();
3065 midi_path += msp.to_string();
3067 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3068 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3070 /* find all sources, but don't use this snapshot because the
3071 state file on disk still references sources we may have already
3075 find_all_sources_across_snapshots (all_sources, true);
3077 /* add our current source list
3080 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3081 boost::shared_ptr<FileSource> fs;
3082 SourceMap::iterator tmp = i;
3085 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3087 /* this is mostly for windows which doesn't allow file
3088 * renaming if the file is in use. But we don't special
3089 * case it because we need to know if this causes
3090 * problems, and the easiest way to notice that is to
3091 * keep it in place for all platforms.
3096 if (!fs->is_stub()) {
3098 if (playlists->source_use_count (fs) != 0) {
3099 all_sources.insert (fs->path());
3102 /* we might not remove this source from disk, because it may be used
3103 by other snapshots, but its not being used in this version
3104 so lets get rid of it now, along with any representative regions
3108 RegionFactory::remove_regions_using_source (i->second);
3110 // also remove source from all_sources
3112 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3113 spath = Glib::path_get_basename (*j);
3114 if (spath == i->second->name()) {
3115 all_sources.erase (j);
3128 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3133 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3135 tmppath1 = canonical_path (spath);
3136 tmppath2 = canonical_path ((*i));
3138 if (tmppath1 == tmppath2) {
3145 unused.push_back (spath);
3149 /* now try to move all unused files into the "dead" directory(ies) */
3151 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3156 /* don't move the file across filesystems, just
3157 stick it in the `dead_dir_name' directory
3158 on whichever filesystem it was already on.
3161 if ((*x).find ("/sounds/") != string::npos) {
3163 /* old school, go up 1 level */
3165 newpath = Glib::path_get_dirname (*x); // "sounds"
3166 newpath = Glib::path_get_dirname (newpath); // "session-name"
3170 /* new school, go up 4 levels */
3172 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3173 newpath = Glib::path_get_dirname (newpath); // "session-name"
3174 newpath = Glib::path_get_dirname (newpath); // "interchange"
3175 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3178 newpath = Glib::build_filename (newpath, dead_dir_name);
3180 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3181 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3185 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3187 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3189 /* the new path already exists, try versioning */
3191 char buf[PATH_MAX+1];
3195 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3198 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3199 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3203 if (version == 999) {
3204 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3208 newpath = newpath_v;
3213 /* it doesn't exist, or we can't read it or something */
3217 g_stat ((*x).c_str(), &statbuf);
3219 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3220 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3221 (*x), newpath, strerror (errno))
3226 /* see if there an easy to find peakfile for this file, and remove it.
3229 string base = Glib::path_get_basename (*x);
3230 base += "%A"; /* this is what we add for the channel suffix of all native files,
3231 or for the first channel of embedded files. it will miss
3232 some peakfiles for other channels
3234 string peakpath = construct_peak_filepath (base);
3236 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3237 if (::g_unlink (peakpath.c_str()) != 0) {
3238 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3239 peakpath, _path, strerror (errno))
3241 /* try to back out */
3242 ::rename (newpath.c_str(), _path.c_str());
3247 rep.paths.push_back (*x);
3248 rep.space += statbuf.st_size;
3251 /* dump the history list */
3255 /* save state so we don't end up a session file
3256 referring to non-existent sources.
3263 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3269 Session::cleanup_trash_sources (CleanupReport& rep)
3271 // FIXME: needs adaptation for MIDI
3273 vector<space_and_path>::iterator i;
3279 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3281 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3283 clear_directory (dead_dir, &rep.space, &rep.paths);
3290 Session::set_dirty ()
3292 /* never mark session dirty during loading */
3294 if (_state_of_the_state & Loading) {
3298 bool was_dirty = dirty();
3300 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3304 DirtyChanged(); /* EMIT SIGNAL */
3310 Session::set_clean ()
3312 bool was_dirty = dirty();
3314 _state_of_the_state = Clean;
3318 DirtyChanged(); /* EMIT SIGNAL */
3323 Session::set_deletion_in_progress ()
3325 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3329 Session::clear_deletion_in_progress ()
3331 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3335 Session::add_controllable (boost::shared_ptr<Controllable> c)
3337 /* this adds a controllable to the list managed by the Session.
3338 this is a subset of those managed by the Controllable class
3339 itself, and represents the only ones whose state will be saved
3340 as part of the session.
3343 Glib::Threads::Mutex::Lock lm (controllables_lock);
3344 controllables.insert (c);
3347 struct null_deleter { void operator()(void const *) const {} };
3350 Session::remove_controllable (Controllable* c)
3352 if (_state_of_the_state & Deletion) {
3356 Glib::Threads::Mutex::Lock lm (controllables_lock);
3358 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3360 if (x != controllables.end()) {
3361 controllables.erase (x);
3365 boost::shared_ptr<Controllable>
3366 Session::controllable_by_id (const PBD::ID& id)
3368 Glib::Threads::Mutex::Lock lm (controllables_lock);
3370 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3371 if ((*i)->id() == id) {
3376 return boost::shared_ptr<Controllable>();
3379 boost::shared_ptr<Controllable>
3380 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3382 boost::shared_ptr<Controllable> c;
3383 boost::shared_ptr<Route> r;
3385 switch (desc.top_level_type()) {
3386 case ControllableDescriptor::NamedRoute:
3388 std::string str = desc.top_level_name();
3389 if (str == "Master" || str == "master") {
3391 } else if (str == "control" || str == "listen") {
3394 r = route_by_name (desc.top_level_name());
3399 case ControllableDescriptor::RemoteControlID:
3400 r = route_by_remote_id (desc.rid());
3403 case ControllableDescriptor::SelectionCount:
3404 r = route_by_selected_count (desc.selection_id());
3412 switch (desc.subtype()) {
3413 case ControllableDescriptor::Gain:
3414 c = r->gain_control ();
3417 case ControllableDescriptor::Trim:
3418 c = r->trim()->gain_control ();
3421 case ControllableDescriptor::Solo:
3422 c = r->solo_control();
3425 case ControllableDescriptor::Mute:
3426 c = r->mute_control();
3429 case ControllableDescriptor::Recenable:
3431 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3434 c = t->rec_enable_control ();
3439 case ControllableDescriptor::PanDirection:
3440 c = r->pan_azimuth_control();
3443 case ControllableDescriptor::PanWidth:
3444 c = r->pan_width_control();
3447 case ControllableDescriptor::PanElevation:
3448 c = r->pan_elevation_control();
3451 case ControllableDescriptor::Balance:
3452 /* XXX simple pan control */
3455 case ControllableDescriptor::PluginParameter:
3457 uint32_t plugin = desc.target (0);
3458 uint32_t parameter_index = desc.target (1);
3460 /* revert to zero based counting */
3466 if (parameter_index > 0) {
3470 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3473 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3474 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3479 case ControllableDescriptor::SendGain: {
3480 uint32_t send = desc.target (0);
3484 c = r->send_level_controllable (send);
3489 /* relax and return a null pointer */
3497 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3500 Stateful::add_instant_xml (node, _path);
3503 if (write_to_config) {
3504 Config->add_instant_xml (node);
3509 Session::instant_xml (const string& node_name)
3511 return Stateful::instant_xml (node_name, _path);
3515 Session::save_history (string snapshot_name)
3523 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3524 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3528 if (snapshot_name.empty()) {
3529 snapshot_name = _current_snapshot_name;
3532 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3533 const string backup_filename = history_filename + backup_suffix;
3534 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3535 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3537 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3538 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3539 error << _("could not backup old history file, current history not saved") << endmsg;
3544 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3546 if (!tree.write (xml_path))
3548 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3550 if (g_remove (xml_path.c_str()) != 0) {
3551 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3552 xml_path, g_strerror (errno)) << endmsg;
3554 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3555 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3556 backup_path, g_strerror (errno)) << endmsg;
3566 Session::restore_history (string snapshot_name)
3570 if (snapshot_name.empty()) {
3571 snapshot_name = _current_snapshot_name;
3574 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3575 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3577 info << "Loading history from " << xml_path << endmsg;
3579 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3580 info << string_compose (_("%1: no history file \"%2\" for this session."),
3581 _name, xml_path) << endmsg;
3585 if (!tree.read (xml_path)) {
3586 error << string_compose (_("Could not understand session history file \"%1\""),
3587 xml_path) << endmsg;
3594 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3597 UndoTransaction* ut = new UndoTransaction ();
3600 ut->set_name(t->property("name")->value());
3601 stringstream ss(t->property("tv-sec")->value());
3603 ss.str(t->property("tv-usec")->value());
3605 ut->set_timestamp(tv);
3607 for (XMLNodeConstIterator child_it = t->children().begin();
3608 child_it != t->children().end(); child_it++)
3610 XMLNode *n = *child_it;
3613 if (n->name() == "MementoCommand" ||
3614 n->name() == "MementoUndoCommand" ||
3615 n->name() == "MementoRedoCommand") {
3617 if ((c = memento_command_factory(n))) {
3621 } else if (n->name() == "NoteDiffCommand") {
3622 PBD::ID id (n->property("midi-source")->value());
3623 boost::shared_ptr<MidiSource> midi_source =
3624 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3626 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3628 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3631 } else if (n->name() == "SysExDiffCommand") {
3633 PBD::ID id (n->property("midi-source")->value());
3634 boost::shared_ptr<MidiSource> midi_source =
3635 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3637 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3639 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3642 } else if (n->name() == "PatchChangeDiffCommand") {
3644 PBD::ID id (n->property("midi-source")->value());
3645 boost::shared_ptr<MidiSource> midi_source =
3646 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3648 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3650 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3653 } else if (n->name() == "StatefulDiffCommand") {
3654 if ((c = stateful_diff_command_factory (n))) {
3655 ut->add_command (c);
3658 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3669 Session::config_changed (std::string p, bool ours)
3675 if (p == "seamless-loop") {
3677 } else if (p == "rf-speed") {
3679 } else if (p == "auto-loop") {
3681 } else if (p == "auto-input") {
3683 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3684 /* auto-input only makes a difference if we're rolling */
3685 set_track_monitor_input_status (!config.get_auto_input());
3688 } else if (p == "punch-in") {
3692 if ((location = _locations->auto_punch_location()) != 0) {
3694 if (config.get_punch_in ()) {
3695 replace_event (SessionEvent::PunchIn, location->start());
3697 remove_event (location->start(), SessionEvent::PunchIn);
3701 } else if (p == "punch-out") {
3705 if ((location = _locations->auto_punch_location()) != 0) {
3707 if (config.get_punch_out()) {
3708 replace_event (SessionEvent::PunchOut, location->end());
3710 clear_events (SessionEvent::PunchOut);
3714 } else if (p == "edit-mode") {
3716 Glib::Threads::Mutex::Lock lm (playlists->lock);
3718 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3719 (*i)->set_edit_mode (Config->get_edit_mode ());
3722 } else if (p == "use-video-sync") {
3724 waiting_for_sync_offset = config.get_use_video_sync();
3726 } else if (p == "mmc-control") {
3728 //poke_midi_thread ();
3730 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3732 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3734 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3736 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3738 } else if (p == "midi-control") {
3740 //poke_midi_thread ();
3742 } else if (p == "raid-path") {
3744 setup_raid_path (config.get_raid_path());
3746 } else if (p == "timecode-format") {
3750 } else if (p == "video-pullup") {
3754 } else if (p == "seamless-loop") {
3756 if (play_loop && transport_rolling()) {
3757 // to reset diskstreams etc
3758 request_play_loop (true);
3761 } else if (p == "rf-speed") {
3763 cumulative_rf_motion = 0;
3766 } else if (p == "click-sound") {
3768 setup_click_sounds (1);
3770 } else if (p == "click-emphasis-sound") {
3772 setup_click_sounds (-1);
3774 } else if (p == "clicking") {
3776 if (Config->get_clicking()) {
3777 if (_click_io && click_data) { // don't require emphasis data
3784 } else if (p == "click-gain") {
3787 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3790 } else if (p == "send-mtc") {
3792 if (Config->get_send_mtc ()) {
3793 /* mark us ready to send */
3794 next_quarter_frame_to_send = 0;
3797 } else if (p == "send-mmc") {
3799 _mmc->enable_send (Config->get_send_mmc ());
3801 } else if (p == "midi-feedback") {
3803 session_midi_feedback = Config->get_midi_feedback();
3805 } else if (p == "jack-time-master") {
3807 engine().reset_timebase ();
3809 } else if (p == "native-file-header-format") {
3811 if (!first_file_header_format_reset) {
3812 reset_native_file_format ();
3815 first_file_header_format_reset = false;
3817 } else if (p == "native-file-data-format") {
3819 if (!first_file_data_format_reset) {
3820 reset_native_file_format ();
3823 first_file_data_format_reset = false;
3825 } else if (p == "external-sync") {
3826 if (!config.get_external_sync()) {
3827 drop_sync_source ();
3829 switch_to_sync_source (Config->get_sync_source());
3831 } else if (p == "denormal-model") {
3833 } else if (p == "history-depth") {
3834 set_history_depth (Config->get_history_depth());
3835 } else if (p == "remote-model") {
3836 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3839 } else if (p == "initial-program-change") {
3841 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3844 buf[0] = MIDI::program; // channel zero by default
3845 buf[1] = (Config->get_initial_program_change() & 0x7f);
3847 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3849 } else if (p == "solo-mute-override") {
3850 // catch_up_on_solo_mute_override ();
3851 } else if (p == "listen-position" || p == "pfl-position") {
3852 listen_position_changed ();
3853 } else if (p == "solo-control-is-listen-control") {
3854 solo_control_mode_changed ();
3855 } else if (p == "solo-mute-gain") {
3856 _solo_cut_control->Changed();
3857 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3858 last_timecode_valid = false;
3859 } else if (p == "playback-buffer-seconds") {
3860 AudioSource::allocate_working_buffers (frame_rate());
3861 } else if (p == "ltc-source-port") {
3862 reconnect_ltc_input ();
3863 } else if (p == "ltc-sink-port") {
3864 reconnect_ltc_output ();
3865 } else if (p == "timecode-generator-offset") {
3866 ltc_tx_parse_offset();
3867 } else if (p == "auto-return-target-list") {
3868 follow_playhead_priority ();
3875 Session::set_history_depth (uint32_t d)
3877 _history.set_depth (d);
3881 Session::load_diskstreams_2X (XMLNode const & node, int)
3884 XMLNodeConstIterator citer;
3886 clist = node.children();
3888 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3891 /* diskstreams added automatically by DiskstreamCreated handler */
3892 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3893 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3894 _diskstreams_2X.push_back (dsp);
3896 error << _("Session: unknown diskstream type in XML") << endmsg;
3900 catch (failed_constructor& err) {
3901 error << _("Session: could not load diskstream via XML state") << endmsg;
3909 /** Connect things to the MMC object */
3911 Session::setup_midi_machine_control ()
3913 _mmc = new MIDI::MachineControl;
3915 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
3916 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
3918 if (!async_out || !async_out) {
3922 /* XXXX argh, passing raw pointers back into libmidi++ */
3924 MIDI::Port* mmc_in = async_in.get();
3925 MIDI::Port* mmc_out = async_out.get();
3927 _mmc->set_ports (mmc_in, mmc_out);
3929 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3930 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3931 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3932 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3933 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3934 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3935 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3936 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3937 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3938 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3939 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3940 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3941 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3943 /* also handle MIDI SPP because its so common */
3945 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3946 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3947 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3950 boost::shared_ptr<Controllable>
3951 Session::solo_cut_control() const
3953 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3954 controls in Ardour that currently get presented to the user in the GUI that require
3955 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3957 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3958 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3962 return _solo_cut_control;
3966 Session::save_snapshot_name (const std::string & n)
3968 /* assure Stateful::_instant_xml is loaded
3969 * add_instant_xml() only adds to existing data and defaults
3970 * to use an empty Tree otherwise
3972 instant_xml ("LastUsedSnapshot");
3974 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
3975 last_used_snapshot->add_property ("name", string(n));
3976 add_instant_xml (*last_used_snapshot, false);
3980 Session::set_snapshot_name (const std::string & n)
3982 _current_snapshot_name = n;
3983 save_snapshot_name (n);
3987 Session::rename (const std::string& new_name)
3989 string legal_name = legalize_for_path (new_name);
3995 string const old_sources_root = _session_dir->sources_root();
3997 if (!_writable || (_state_of_the_state & CannotSave)) {
3998 error << _("Cannot rename read-only session.") << endmsg;
3999 return 0; // don't show "messed up" warning
4001 if (record_status() == Recording) {
4002 error << _("Cannot rename session while recording") << endmsg;
4003 return 0; // don't show "messed up" warning
4006 StateProtector stp (this);
4011 * interchange subdirectory
4015 * Backup files are left unchanged and not renamed.
4018 /* Windows requires that we close all files before attempting the
4019 * rename. This works on other platforms, but isn't necessary there.
4020 * Leave it in place for all platforms though, since it may help
4021 * catch issues that could arise if the way Source files work ever
4022 * change (since most developers are not using Windows).
4025 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4026 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4032 /* pass one: not 100% safe check that the new directory names don't
4036 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4040 /* this is a stupid hack because Glib::path_get_dirname() is
4041 * lexical-only, and so passing it /a/b/c/ gives a different
4042 * result than passing it /a/b/c ...
4045 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4046 oldstr = oldstr.substr (0, oldstr.length() - 1);
4049 string base = Glib::path_get_dirname (oldstr);
4051 newstr = Glib::build_filename (base, legal_name);
4053 cerr << "Looking for " << newstr << endl;
4055 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4056 cerr << " exists\n";
4065 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4071 /* this is a stupid hack because Glib::path_get_dirname() is
4072 * lexical-only, and so passing it /a/b/c/ gives a different
4073 * result than passing it /a/b/c ...
4076 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4077 oldstr = oldstr.substr (0, oldstr.length() - 1);
4080 string base = Glib::path_get_dirname (oldstr);
4081 newstr = Glib::build_filename (base, legal_name);
4083 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4085 cerr << "Rename " << oldstr << " => " << newstr << endl;
4086 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4087 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4088 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4092 /* Reset path in "session dirs" */
4097 /* reset primary SessionDirectory object */
4100 (*_session_dir) = newstr;
4105 /* now rename directory below session_dir/interchange */
4107 string old_interchange_dir;
4108 string new_interchange_dir;
4110 /* use newstr here because we renamed the path
4111 * (folder/directory) that used to be oldstr to newstr above
4114 v.push_back (newstr);
4115 v.push_back (interchange_dir_name);
4116 v.push_back (Glib::path_get_basename (oldstr));
4118 old_interchange_dir = Glib::build_filename (v);
4121 v.push_back (newstr);
4122 v.push_back (interchange_dir_name);
4123 v.push_back (legal_name);
4125 new_interchange_dir = Glib::build_filename (v);
4127 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4129 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4130 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4131 old_interchange_dir, new_interchange_dir,
4134 error << string_compose (_("renaming %s as %2 failed (%3)"),
4135 old_interchange_dir, new_interchange_dir,
4144 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4145 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4147 cerr << "Rename " << oldstr << " => " << newstr << endl;
4149 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4150 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4151 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4157 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4159 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4160 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4162 cerr << "Rename " << oldstr << " => " << newstr << endl;
4164 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4165 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4166 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4171 /* remove old name from recent sessions */
4172 remove_recent_sessions (_path);
4175 /* update file source paths */
4177 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4178 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4180 string p = fs->path ();
4181 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4183 SourceFactory::setup_peakfile(i->second, true);
4187 set_snapshot_name (new_name);
4192 /* save state again to get everything just right */
4194 save_state (_current_snapshot_name);
4196 /* add to recent sessions */
4198 store_recent_sessions (new_name, _path);
4204 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4206 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4210 if (!tree.read (xmlpath)) {
4218 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4221 bool found_sr = false;
4222 bool found_data_format = false;
4224 if (get_session_info_from_path (tree, xmlpath)) {
4230 const XMLProperty* prop;
4231 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4232 sample_rate = atoi (prop->value());
4236 const XMLNodeList& children (tree.root()->children());
4237 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4238 const XMLNode* child = *c;
4239 if (child->name() == "Config") {
4240 const XMLNodeList& options (child->children());
4241 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4242 const XMLNode* option = *oc;
4243 const XMLProperty* name = option->property("name");
4249 if (name->value() == "native-file-data-format") {
4250 const XMLProperty* value = option->property ("value");
4252 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4254 found_data_format = true;
4260 if (found_data_format) {
4265 return !(found_sr && found_data_format); // zero if they are both found
4269 Session::get_snapshot_from_instant (const std::string& session_dir)
4271 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4273 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4278 if (!tree.read (instant_xml_path)) {
4282 const XMLProperty* prop;
4283 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4284 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4285 return prop->value();
4291 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4292 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4295 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4299 SourcePathMap source_path_map;
4301 boost::shared_ptr<AudioFileSource> afs;
4306 Glib::Threads::Mutex::Lock lm (source_lock);
4308 cerr << " total sources = " << sources.size();
4310 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4311 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4317 if (fs->within_session()) {
4321 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4322 source_path_map[fs->path()].push_back (fs);
4324 SeveralFileSources v;
4326 source_path_map.insert (make_pair (fs->path(), v));
4332 cerr << " fsources = " << total << endl;
4334 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4336 /* tell caller where we are */
4338 string old_path = i->first;
4340 callback (n, total, old_path);
4342 cerr << old_path << endl;
4346 switch (i->second.front()->type()) {
4347 case DataType::AUDIO:
4348 new_path = new_audio_source_path_for_embedded (old_path);
4351 case DataType::MIDI:
4352 /* XXX not implemented yet */
4356 if (new_path.empty()) {
4360 cerr << "Move " << old_path << " => " << new_path << endl;
4362 if (!copy_file (old_path, new_path)) {
4363 cerr << "failed !\n";
4367 /* make sure we stop looking in the external
4368 dir/folder. Remember, this is an all-or-nothing
4369 operations, it doesn't merge just some files.
4371 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4373 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4374 (*f)->set_path (new_path);
4379 save_state ("", false, false);
4385 bool accept_all_files (string const &, void *)
4391 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4393 /* 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.
4398 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4400 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4402 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4404 v.push_back (new_session_folder); /* full path */
4405 v.push_back (interchange_dir_name);
4406 v.push_back (new_session_path); /* just one directory/folder */
4407 v.push_back (typedir);
4408 v.push_back (Glib::path_get_basename (old_path));
4410 return Glib::build_filename (v);
4414 Session::save_as (SaveAs& saveas)
4416 vector<string> files;
4417 string current_folder = Glib::path_get_dirname (_path);
4418 string new_folder = legalize_for_path (saveas.new_name);
4419 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4420 int64_t total_bytes = 0;
4424 int32_t internal_file_cnt = 0;
4426 vector<string> do_not_copy_extensions;
4427 do_not_copy_extensions.push_back (statefile_suffix);
4428 do_not_copy_extensions.push_back (pending_suffix);
4429 do_not_copy_extensions.push_back (backup_suffix);
4430 do_not_copy_extensions.push_back (temp_suffix);
4431 do_not_copy_extensions.push_back (history_suffix);
4433 /* get total size */
4435 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4437 /* need to clear this because
4438 * find_files_matching_filter() is cumulative
4443 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4445 all += files.size();
4447 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4449 g_stat ((*i).c_str(), &gsb);
4450 total_bytes += gsb.st_size;
4454 /* save old values so we can switch back if we are not switching to the new session */
4456 string old_path = _path;
4457 string old_name = _name;
4458 string old_snapshot = _current_snapshot_name;
4459 string old_sd = _session_dir->root_path();
4460 vector<string> old_search_path[DataType::num_types];
4461 string old_config_search_path[DataType::num_types];
4463 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4464 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4465 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4466 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4468 /* switch session directory */
4470 (*_session_dir) = to_dir;
4472 /* create new tree */
4474 if (!_session_dir->create()) {
4475 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4480 /* copy all relevant files. Find each location in session_dirs,
4481 * and copy files from there to target.
4484 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4486 /* need to clear this because
4487 * find_files_matching_filter() is cumulative
4492 const size_t prefix_len = (*sd).path.size();
4494 /* Work just on the files within this session dir */
4496 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4498 /* add dir separator to protect against collisions with
4499 * track names (e.g. track named "audiofiles" or
4503 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4504 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4505 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4507 /* copy all the files. Handling is different for media files
4508 than others because of the *silly* subtree we have below the interchange
4509 folder. That really was a bad idea, but I'm not fixing it as part of
4510 implementing ::save_as().
4513 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4515 std::string from = *i;
4518 string filename = Glib::path_get_basename (from);
4519 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4520 if (filename == ".DS_STORE") {
4525 if (from.find (audiofile_dir_string) != string::npos) {
4527 /* audio file: only copy if asked */
4529 if (saveas.include_media && saveas.copy_media) {
4531 string to = make_new_media_path (*i, to_dir, new_folder);
4533 info << "media file copying from " << from << " to " << to << endmsg;
4535 if (!copy_file (from, to)) {
4536 throw Glib::FileError (Glib::FileError::IO_ERROR,
4537 string_compose(_("\ncopying \"%1\" failed !"), from));
4541 /* we found media files inside the session folder */
4543 internal_file_cnt++;
4545 } else if (from.find (midifile_dir_string) != string::npos) {
4547 /* midi file: always copy unless
4548 * creating an empty new session
4551 if (saveas.include_media) {
4553 string to = make_new_media_path (*i, to_dir, new_folder);
4555 info << "media file copying from " << from << " to " << to << endmsg;
4557 if (!copy_file (from, to)) {
4558 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4562 /* we found media files inside the session folder */
4564 internal_file_cnt++;
4566 } else if (from.find (analysis_dir_string) != string::npos) {
4568 /* make sure analysis dir exists in
4569 * new session folder, but we're not
4570 * copying analysis files here, see
4574 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4579 /* normal non-media file. Don't copy state, history, etc.
4582 bool do_copy = true;
4584 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4585 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4586 /* end of filename matches extension, do not copy file */
4592 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4593 /* don't copy peakfiles if
4594 * we're not copying media
4600 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4602 info << "attempting to make directory/folder " << to << endmsg;
4604 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4605 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4608 info << "attempting to copy " << from << " to " << to << endmsg;
4610 if (!copy_file (from, to)) {
4611 throw Glib::FileError (Glib::FileError::IO_ERROR,
4612 string_compose(_("\ncopying \"%1\" failed !"), from));
4617 /* measure file size even if we're not going to copy so that our Progress
4618 signals are correct, since we included these do-not-copy files
4619 in the computation of the total size and file count.
4623 g_stat (from.c_str(), &gsb);
4624 copied += gsb.st_size;
4627 double fraction = (double) copied / total_bytes;
4629 bool keep_going = true;
4631 if (saveas.copy_media) {
4633 /* no need or expectation of this if
4634 * media is not being copied, because
4635 * it will be fast(ish).
4638 /* tell someone "X percent, file M of N"; M is one-based */
4640 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4648 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4654 /* copy optional folders, if any */
4656 string old = plugins_dir ();
4657 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4658 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4659 copy_files (old, newdir);
4662 old = externals_dir ();
4663 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4664 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4665 copy_files (old, newdir);
4668 old = automation_dir ();
4669 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4670 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4671 copy_files (old, newdir);
4674 if (saveas.include_media) {
4676 if (saveas.copy_media) {
4677 #ifndef PLATFORM_WINDOWS
4678 /* There are problems with analysis files on
4679 * Windows, because they used a colon in their
4680 * names as late as 4.0. Colons are not legal
4681 * under Windows even if NTFS allows them.
4683 * This is a tricky problem to solve so for
4684 * just don't copy these files. They will be
4685 * regenerated as-needed anyway, subject to the
4686 * existing issue that the filenames will be
4687 * rejected by Windows, which is a separate
4688 * problem (though related).
4691 /* only needed if we are copying media, since the
4692 * analysis data refers to media data
4695 old = analysis_dir ();
4696 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4697 string newdir = Glib::build_filename (to_dir, "analysis");
4698 copy_files (old, newdir);
4700 #endif /* PLATFORM_WINDOWS */
4706 set_snapshot_name (saveas.new_name);
4707 _name = saveas.new_name;
4709 if (saveas.include_media && !saveas.copy_media) {
4711 /* reset search paths of the new session (which we're pretending to be right now) to
4712 include the original session search path, so we can still find all audio.
4715 if (internal_file_cnt) {
4716 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4717 ensure_search_path_includes (*s, DataType::AUDIO);
4718 cerr << "be sure to include " << *s << " for audio" << endl;
4721 /* we do not do this for MIDI because we copy
4722 all MIDI files if saveas.include_media is
4728 bool was_dirty = dirty ();
4730 save_state ("", false, false, !saveas.include_media);
4731 save_default_options ();
4733 if (saveas.copy_media && saveas.copy_external) {
4734 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4735 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4739 saveas.final_session_folder_name = _path;
4741 store_recent_sessions (_name, _path);
4743 if (!saveas.switch_to) {
4745 /* switch back to the way things were */
4749 set_snapshot_name (old_snapshot);
4751 (*_session_dir) = old_sd;
4757 if (internal_file_cnt) {
4758 /* reset these to their original values */
4759 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4760 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4765 /* prune session dirs, and update disk space statistics
4770 session_dirs.clear ();
4771 session_dirs.push_back (sp);
4772 refresh_disk_space ();
4774 /* ensure that all existing tracks reset their current capture source paths
4776 reset_write_sources (true, true);
4778 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4779 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4782 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4783 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4789 if (fs->within_session()) {
4790 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4791 fs->set_path (newpath);
4796 } catch (Glib::FileError& e) {
4798 saveas.failure_message = e.what();
4800 /* recursively remove all the directories */
4802 remove_directory (to_dir);
4810 saveas.failure_message = _("unknown reason");
4812 /* recursively remove all the directories */
4814 remove_directory (to_dir);