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, _base_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 _base_frame_rate = atoi (prop->value());
1317 _nominal_frame_rate = _base_frame_rate;
1319 assert (AudioEngine::instance()->running ());
1320 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1321 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1322 if (r.get_value_or (0)) {
1328 setup_raid_path(_session_dir->root_path());
1330 if ((prop = node.property (X_("id-counter"))) != 0) {
1332 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1333 ID::init_counter (x);
1335 /* old sessions used a timebased counter, so fake
1336 the startup ID counter based on a standard
1341 ID::init_counter (now);
1344 if ((prop = node.property (X_("name-counter"))) != 0) {
1345 init_name_id_counter (atoi (prop->value()));
1348 if ((prop = node.property (X_("event-counter"))) != 0) {
1349 Evoral::init_event_id_counter (atoi (prop->value()));
1352 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1353 _midi_ports->set_midi_port_states (child->children());
1356 IO::disable_connecting ();
1358 Stateful::save_extra_xml (node);
1360 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1361 load_options (*child);
1362 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1363 load_options (*child);
1365 error << _("Session: XML state has no options section") << endmsg;
1368 if (version >= 3000) {
1369 if ((child = find_named_node (node, "Metadata")) == 0) {
1370 warning << _("Session: XML state has no metadata section") << endmsg;
1371 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1376 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1377 _speakers->set_state (*child, version);
1380 if ((child = find_named_node (node, "Sources")) == 0) {
1381 error << _("Session: XML state has no sources section") << endmsg;
1383 } else if (load_sources (*child)) {
1387 if ((child = find_named_node (node, "TempoMap")) == 0) {
1388 error << _("Session: XML state has no Tempo Map section") << endmsg;
1390 } else if (_tempo_map->set_state (*child, version)) {
1394 if ((child = find_named_node (node, "Locations")) == 0) {
1395 error << _("Session: XML state has no locations section") << endmsg;
1397 } else if (_locations->set_state (*child, version)) {
1401 locations_changed ();
1403 if (_session_range_location) {
1404 AudioFileSource::set_header_position_offset (_session_range_location->start());
1407 if ((child = find_named_node (node, "Regions")) == 0) {
1408 error << _("Session: XML state has no Regions section") << endmsg;
1410 } else if (load_regions (*child)) {
1414 if ((child = find_named_node (node, "Playlists")) == 0) {
1415 error << _("Session: XML state has no playlists section") << endmsg;
1417 } else if (playlists->load (*this, *child)) {
1421 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1423 } else if (playlists->load_unused (*this, *child)) {
1427 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1428 if (load_compounds (*child)) {
1433 if (version >= 3000) {
1434 if ((child = find_named_node (node, "Bundles")) == 0) {
1435 warning << _("Session: XML state has no bundles section") << endmsg;
1438 /* We can't load Bundles yet as they need to be able
1439 to convert from port names to Port objects, which can't happen until
1441 _bundle_xml_node = new XMLNode (*child);
1445 if (version < 3000) {
1446 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1447 error << _("Session: XML state has no diskstreams section") << endmsg;
1449 } else if (load_diskstreams_2X (*child, version)) {
1454 if ((child = find_named_node (node, "Routes")) == 0) {
1455 error << _("Session: XML state has no routes section") << endmsg;
1457 } else if (load_routes (*child, version)) {
1461 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1462 _diskstreams_2X.clear ();
1464 if (version >= 3000) {
1466 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1467 error << _("Session: XML state has no route groups section") << endmsg;
1469 } else if (load_route_groups (*child, version)) {
1473 } else if (version < 3000) {
1475 if ((child = find_named_node (node, "EditGroups")) == 0) {
1476 error << _("Session: XML state has no edit groups section") << endmsg;
1478 } else if (load_route_groups (*child, version)) {
1482 if ((child = find_named_node (node, "MixGroups")) == 0) {
1483 error << _("Session: XML state has no mix groups section") << endmsg;
1485 } else if (load_route_groups (*child, version)) {
1490 if ((child = find_named_node (node, "Click")) == 0) {
1491 warning << _("Session: XML state has no click section") << endmsg;
1492 } else if (_click_io) {
1493 setup_click_state (&node);
1496 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1497 ControlProtocolManager::instance().set_state (*child, version);
1500 if ((child = find_named_node (node, "Script"))) {
1501 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1502 if (!(*n)->is_content ()) { continue; }
1504 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1506 Glib::Threads::Mutex::Lock lm (lua_lock);
1507 (*_lua_load)(std::string ((const char*)buf, size));
1508 } catch (luabridge::LuaException const& e) {
1509 cerr << "LuaException:" << e.what () << endl;
1515 update_route_record_state ();
1517 /* here beginneth the second phase ... */
1518 set_snapshot_name (_current_snapshot_name);
1520 StateReady (); /* EMIT SIGNAL */
1533 Session::load_routes (const XMLNode& node, int version)
1536 XMLNodeConstIterator niter;
1537 RouteList new_routes;
1539 nlist = node.children();
1543 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1545 boost::shared_ptr<Route> route;
1546 if (version < 3000) {
1547 route = XMLRouteFactory_2X (**niter, version);
1549 route = XMLRouteFactory (**niter, version);
1553 error << _("Session: cannot create Route from XML description.") << endmsg;
1557 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1559 new_routes.push_back (route);
1562 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1564 add_routes (new_routes, false, false, false);
1566 BootMessage (_("Finished adding tracks/busses"));
1571 boost::shared_ptr<Route>
1572 Session::XMLRouteFactory (const XMLNode& node, int version)
1574 boost::shared_ptr<Route> ret;
1576 if (node.name() != "Route") {
1580 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1582 DataType type = DataType::AUDIO;
1583 const XMLProperty* prop = node.property("default-type");
1586 type = DataType (prop->value());
1589 assert (type != DataType::NIL);
1593 boost::shared_ptr<Track> track;
1595 if (type == DataType::AUDIO) {
1596 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1598 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1601 if (track->init()) {
1605 if (track->set_state (node, version)) {
1609 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1610 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1615 enum Route::Flag flags = Route::Flag(0);
1616 const XMLProperty* prop = node.property("flags");
1618 flags = Route::Flag (string_2_enum (prop->value(), flags));
1621 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1623 if (r->init () == 0 && r->set_state (node, version) == 0) {
1624 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1625 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1634 boost::shared_ptr<Route>
1635 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1637 boost::shared_ptr<Route> ret;
1639 if (node.name() != "Route") {
1643 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1645 ds_prop = node.property (X_("diskstream"));
1648 DataType type = DataType::AUDIO;
1649 const XMLProperty* prop = node.property("default-type");
1652 type = DataType (prop->value());
1655 assert (type != DataType::NIL);
1659 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1660 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1664 if (i == _diskstreams_2X.end()) {
1665 error << _("Could not find diskstream for route") << endmsg;
1666 return boost::shared_ptr<Route> ();
1669 boost::shared_ptr<Track> track;
1671 if (type == DataType::AUDIO) {
1672 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1674 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1677 if (track->init()) {
1681 if (track->set_state (node, version)) {
1685 track->set_diskstream (*i);
1687 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1688 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1693 enum Route::Flag flags = Route::Flag(0);
1694 const XMLProperty* prop = node.property("flags");
1696 flags = Route::Flag (string_2_enum (prop->value(), flags));
1699 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1701 if (r->init () == 0 && r->set_state (node, version) == 0) {
1702 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1703 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1713 Session::load_regions (const XMLNode& node)
1716 XMLNodeConstIterator niter;
1717 boost::shared_ptr<Region> region;
1719 nlist = node.children();
1723 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1724 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1725 error << _("Session: cannot create Region from XML description.");
1726 const XMLProperty *name = (**niter).property("name");
1729 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1740 Session::load_compounds (const XMLNode& node)
1742 XMLNodeList calist = node.children();
1743 XMLNodeConstIterator caiter;
1744 XMLProperty *caprop;
1746 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1747 XMLNode* ca = *caiter;
1751 if ((caprop = ca->property (X_("original"))) == 0) {
1754 orig_id = caprop->value();
1756 if ((caprop = ca->property (X_("copy"))) == 0) {
1759 copy_id = caprop->value();
1761 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1762 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1764 if (!orig || !copy) {
1765 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1771 RegionFactory::add_compound_association (orig, copy);
1778 Session::load_nested_sources (const XMLNode& node)
1781 XMLNodeConstIterator niter;
1783 nlist = node.children();
1785 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1786 if ((*niter)->name() == "Source") {
1788 /* it may already exist, so don't recreate it unnecessarily
1791 XMLProperty* prop = (*niter)->property (X_("id"));
1793 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1797 ID source_id (prop->value());
1799 if (!source_by_id (source_id)) {
1802 SourceFactory::create (*this, **niter, true);
1804 catch (failed_constructor& err) {
1805 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1812 boost::shared_ptr<Region>
1813 Session::XMLRegionFactory (const XMLNode& node, bool full)
1815 const XMLProperty* type = node.property("type");
1819 const XMLNodeList& nlist = node.children();
1821 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1822 XMLNode *child = (*niter);
1823 if (child->name() == "NestedSource") {
1824 load_nested_sources (*child);
1828 if (!type || type->value() == "audio") {
1829 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1830 } else if (type->value() == "midi") {
1831 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1834 } catch (failed_constructor& err) {
1835 return boost::shared_ptr<Region> ();
1838 return boost::shared_ptr<Region> ();
1841 boost::shared_ptr<AudioRegion>
1842 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1844 const XMLProperty* prop;
1845 boost::shared_ptr<Source> source;
1846 boost::shared_ptr<AudioSource> as;
1848 SourceList master_sources;
1849 uint32_t nchans = 1;
1852 if (node.name() != X_("Region")) {
1853 return boost::shared_ptr<AudioRegion>();
1856 if ((prop = node.property (X_("channels"))) != 0) {
1857 nchans = atoi (prop->value().c_str());
1860 if ((prop = node.property ("name")) == 0) {
1861 cerr << "no name for this region\n";
1865 if ((prop = node.property (X_("source-0"))) == 0) {
1866 if ((prop = node.property ("source")) == 0) {
1867 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1868 return boost::shared_ptr<AudioRegion>();
1872 PBD::ID s_id (prop->value());
1874 if ((source = source_by_id (s_id)) == 0) {
1875 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1876 return boost::shared_ptr<AudioRegion>();
1879 as = boost::dynamic_pointer_cast<AudioSource>(source);
1881 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1882 return boost::shared_ptr<AudioRegion>();
1885 sources.push_back (as);
1887 /* pickup other channels */
1889 for (uint32_t n=1; n < nchans; ++n) {
1890 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1891 if ((prop = node.property (buf)) != 0) {
1893 PBD::ID id2 (prop->value());
1895 if ((source = source_by_id (id2)) == 0) {
1896 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1897 return boost::shared_ptr<AudioRegion>();
1900 as = boost::dynamic_pointer_cast<AudioSource>(source);
1902 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1903 return boost::shared_ptr<AudioRegion>();
1905 sources.push_back (as);
1909 for (uint32_t n = 0; n < nchans; ++n) {
1910 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1911 if ((prop = node.property (buf)) != 0) {
1913 PBD::ID id2 (prop->value());
1915 if ((source = source_by_id (id2)) == 0) {
1916 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1917 return boost::shared_ptr<AudioRegion>();
1920 as = boost::dynamic_pointer_cast<AudioSource>(source);
1922 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1923 return boost::shared_ptr<AudioRegion>();
1925 master_sources.push_back (as);
1930 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1932 /* a final detail: this is the one and only place that we know how long missing files are */
1934 if (region->whole_file()) {
1935 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1936 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1938 sfp->set_length (region->length());
1943 if (!master_sources.empty()) {
1944 if (master_sources.size() != nchans) {
1945 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1947 region->set_master_sources (master_sources);
1955 catch (failed_constructor& err) {
1956 return boost::shared_ptr<AudioRegion>();
1960 boost::shared_ptr<MidiRegion>
1961 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1963 const XMLProperty* prop;
1964 boost::shared_ptr<Source> source;
1965 boost::shared_ptr<MidiSource> ms;
1968 if (node.name() != X_("Region")) {
1969 return boost::shared_ptr<MidiRegion>();
1972 if ((prop = node.property ("name")) == 0) {
1973 cerr << "no name for this region\n";
1977 if ((prop = node.property (X_("source-0"))) == 0) {
1978 if ((prop = node.property ("source")) == 0) {
1979 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1980 return boost::shared_ptr<MidiRegion>();
1984 PBD::ID s_id (prop->value());
1986 if ((source = source_by_id (s_id)) == 0) {
1987 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1988 return boost::shared_ptr<MidiRegion>();
1991 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1993 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1994 return boost::shared_ptr<MidiRegion>();
1997 sources.push_back (ms);
2000 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2001 /* a final detail: this is the one and only place that we know how long missing files are */
2003 if (region->whole_file()) {
2004 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2005 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2007 sfp->set_length (region->length());
2015 catch (failed_constructor& err) {
2016 return boost::shared_ptr<MidiRegion>();
2021 Session::get_sources_as_xml ()
2024 XMLNode* node = new XMLNode (X_("Sources"));
2025 Glib::Threads::Mutex::Lock lm (source_lock);
2027 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2028 node->add_child_nocopy (i->second->get_state());
2035 Session::reset_write_sources (bool mark_write_complete, bool force)
2037 boost::shared_ptr<RouteList> rl = routes.reader();
2038 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2039 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2041 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2042 tr->reset_write_sources(mark_write_complete, force);
2043 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2049 Session::load_sources (const XMLNode& node)
2052 XMLNodeConstIterator niter;
2053 boost::shared_ptr<Source> source; /* don't need this but it stops some
2054 * versions of gcc complaining about
2055 * discarded return values.
2058 nlist = node.children();
2062 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2065 if ((source = XMLSourceFactory (**niter)) == 0) {
2066 error << _("Session: cannot create Source from XML description.") << endmsg;
2069 } catch (MissingSource& err) {
2073 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2074 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2075 PROGRAM_NAME) << endmsg;
2079 if (!no_questions_about_missing_files) {
2080 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2085 switch (user_choice) {
2087 /* user added a new search location, so try again */
2092 /* user asked to quit the entire session load
2097 no_questions_about_missing_files = true;
2101 no_questions_about_missing_files = true;
2108 case DataType::AUDIO:
2109 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2112 case DataType::MIDI:
2113 /* The MIDI file is actually missing so
2114 * just create a new one in the same
2115 * location. Do not announce its
2119 if (!Glib::path_is_absolute (err.path)) {
2120 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2122 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2127 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2128 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2129 /* reset ID to match the missing one */
2130 source->set_id (**niter);
2131 /* Now we can announce it */
2132 SourceFactory::SourceCreated (source);
2143 boost::shared_ptr<Source>
2144 Session::XMLSourceFactory (const XMLNode& node)
2146 if (node.name() != "Source") {
2147 return boost::shared_ptr<Source>();
2151 /* note: do peak building in another thread when loading session state */
2152 return SourceFactory::create (*this, node, true);
2155 catch (failed_constructor& err) {
2156 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2157 return boost::shared_ptr<Source>();
2162 Session::save_template (string template_name, bool replace_existing)
2164 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2168 bool absolute_path = Glib::path_is_absolute (template_name);
2170 /* directory to put the template in */
2171 std::string template_dir_path;
2173 if (!absolute_path) {
2174 std::string user_template_dir(user_template_directory());
2176 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2177 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2178 user_template_dir, g_strerror (errno)) << endmsg;
2182 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2184 template_dir_path = template_name;
2187 if (!ARDOUR::Profile->get_trx()) {
2188 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2189 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2190 template_dir_path) << endmsg;
2194 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2195 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2196 template_dir_path, g_strerror (errno)) << endmsg;
2202 std::string template_file_path;
2204 if (ARDOUR::Profile->get_trx()) {
2205 template_file_path = template_name;
2207 if (absolute_path) {
2208 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2210 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2214 SessionSaveUnderway (); /* EMIT SIGNAL */
2219 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2220 tree.set_root (&get_template());
2223 if (!tree.write (template_file_path)) {
2224 error << _("template not saved") << endmsg;
2228 store_recent_templates (template_file_path);
2234 Session::refresh_disk_space ()
2236 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2238 Glib::Threads::Mutex::Lock lm (space_lock);
2240 /* get freespace on every FS that is part of the session path */
2242 _total_free_4k_blocks = 0;
2243 _total_free_4k_blocks_uncertain = false;
2245 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2247 struct statfs statfsbuf;
2248 statfs (i->path.c_str(), &statfsbuf);
2250 double const scale = statfsbuf.f_bsize / 4096.0;
2252 /* See if this filesystem is read-only */
2253 struct statvfs statvfsbuf;
2254 statvfs (i->path.c_str(), &statvfsbuf);
2256 /* f_bavail can be 0 if it is undefined for whatever
2257 filesystem we are looking at; Samba shares mounted
2258 via GVFS are an example of this.
2260 if (statfsbuf.f_bavail == 0) {
2261 /* block count unknown */
2263 i->blocks_unknown = true;
2264 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2265 /* read-only filesystem */
2267 i->blocks_unknown = false;
2269 /* read/write filesystem with known space */
2270 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2271 i->blocks_unknown = false;
2274 _total_free_4k_blocks += i->blocks;
2275 if (i->blocks_unknown) {
2276 _total_free_4k_blocks_uncertain = true;
2279 #elif defined PLATFORM_WINDOWS
2280 vector<string> scanned_volumes;
2281 vector<string>::iterator j;
2282 vector<space_and_path>::iterator i;
2283 DWORD nSectorsPerCluster, nBytesPerSector,
2284 nFreeClusters, nTotalClusters;
2288 _total_free_4k_blocks = 0;
2290 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2291 strncpy (disk_drive, (*i).path.c_str(), 3);
2295 volume_found = false;
2296 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2298 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2299 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2300 i->blocks = (uint32_t)(nFreeBytes / 4096);
2302 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2303 if (0 == j->compare(disk_drive)) {
2304 volume_found = true;
2309 if (!volume_found) {
2310 scanned_volumes.push_back(disk_drive);
2311 _total_free_4k_blocks += i->blocks;
2316 if (0 == _total_free_4k_blocks) {
2317 strncpy (disk_drive, path().c_str(), 3);
2320 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2322 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2323 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2324 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2331 Session::get_best_session_directory_for_new_audio ()
2333 vector<space_and_path>::iterator i;
2334 string result = _session_dir->root_path();
2336 /* handle common case without system calls */
2338 if (session_dirs.size() == 1) {
2342 /* OK, here's the algorithm we're following here:
2344 We want to select which directory to use for
2345 the next file source to be created. Ideally,
2346 we'd like to use a round-robin process so as to
2347 get maximum performance benefits from splitting
2348 the files across multiple disks.
2350 However, in situations without much diskspace, an
2351 RR approach may end up filling up a filesystem
2352 with new files while others still have space.
2353 Its therefore important to pay some attention to
2354 the freespace in the filesystem holding each
2355 directory as well. However, if we did that by
2356 itself, we'd keep creating new files in the file
2357 system with the most space until it was as full
2358 as all others, thus negating any performance
2359 benefits of this RAID-1 like approach.
2361 So, we use a user-configurable space threshold. If
2362 there are at least 2 filesystems with more than this
2363 much space available, we use RR selection between them.
2364 If not, then we pick the filesystem with the most space.
2366 This gets a good balance between the two
2370 refresh_disk_space ();
2372 int free_enough = 0;
2374 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2375 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2380 if (free_enough >= 2) {
2381 /* use RR selection process, ensuring that the one
2385 i = last_rr_session_dir;
2388 if (++i == session_dirs.end()) {
2389 i = session_dirs.begin();
2392 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2393 SessionDirectory sdir(i->path);
2394 if (sdir.create ()) {
2396 last_rr_session_dir = i;
2401 } while (i != last_rr_session_dir);
2405 /* pick FS with the most freespace (and that
2406 seems to actually work ...)
2409 vector<space_and_path> sorted;
2410 space_and_path_ascending_cmp cmp;
2412 sorted = session_dirs;
2413 sort (sorted.begin(), sorted.end(), cmp);
2415 for (i = sorted.begin(); i != sorted.end(); ++i) {
2416 SessionDirectory sdir(i->path);
2417 if (sdir.create ()) {
2419 last_rr_session_dir = i;
2429 Session::automation_dir () const
2431 return Glib::build_filename (_path, automation_dir_name);
2435 Session::analysis_dir () const
2437 return Glib::build_filename (_path, analysis_dir_name);
2441 Session::plugins_dir () const
2443 return Glib::build_filename (_path, plugins_dir_name);
2447 Session::externals_dir () const
2449 return Glib::build_filename (_path, externals_dir_name);
2453 Session::load_bundles (XMLNode const & node)
2455 XMLNodeList nlist = node.children();
2456 XMLNodeConstIterator niter;
2460 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2461 if ((*niter)->name() == "InputBundle") {
2462 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2463 } else if ((*niter)->name() == "OutputBundle") {
2464 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2466 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2475 Session::load_route_groups (const XMLNode& node, int version)
2477 XMLNodeList nlist = node.children();
2478 XMLNodeConstIterator niter;
2482 if (version >= 3000) {
2484 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2485 if ((*niter)->name() == "RouteGroup") {
2486 RouteGroup* rg = new RouteGroup (*this, "");
2487 add_route_group (rg);
2488 rg->set_state (**niter, version);
2492 } else if (version < 3000) {
2494 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2495 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2496 RouteGroup* rg = new RouteGroup (*this, "");
2497 add_route_group (rg);
2498 rg->set_state (**niter, version);
2507 state_file_filter (const string &str, void* /*arg*/)
2509 return (str.length() > strlen(statefile_suffix) &&
2510 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2514 remove_end(string state)
2516 string statename(state);
2518 string::size_type start,end;
2519 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2520 statename = statename.substr (start+1);
2523 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2524 end = statename.length();
2527 return string(statename.substr (0, end));
2531 Session::possible_states (string path)
2533 vector<string> states;
2534 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2536 transform(states.begin(), states.end(), states.begin(), remove_end);
2538 sort (states.begin(), states.end());
2544 Session::possible_states () const
2546 return possible_states(_path);
2550 Session::add_route_group (RouteGroup* g)
2552 _route_groups.push_back (g);
2553 route_group_added (g); /* EMIT SIGNAL */
2555 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2556 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2557 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2563 Session::remove_route_group (RouteGroup& rg)
2565 list<RouteGroup*>::iterator i;
2567 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2568 _route_groups.erase (i);
2571 route_group_removed (); /* EMIT SIGNAL */
2575 /** Set a new order for our route groups, without adding or removing any.
2576 * @param groups Route group list in the new order.
2579 Session::reorder_route_groups (list<RouteGroup*> groups)
2581 _route_groups = groups;
2583 route_groups_reordered (); /* EMIT SIGNAL */
2589 Session::route_group_by_name (string name)
2591 list<RouteGroup *>::iterator i;
2593 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2594 if ((*i)->name() == name) {
2602 Session::all_route_group() const
2604 return *_all_route_group;
2608 Session::add_commands (vector<Command*> const & cmds)
2610 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2616 Session::add_command (Command* const cmd)
2618 assert (_current_trans);
2619 DEBUG_UNDO_HISTORY (
2620 string_compose ("Current Undo Transaction %1, adding command: %2",
2621 _current_trans->name (),
2623 _current_trans->add_command (cmd);
2626 PBD::StatefulDiffCommand*
2627 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2629 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2635 Session::begin_reversible_command (const string& name)
2637 begin_reversible_command (g_quark_from_string (name.c_str ()));
2640 /** Begin a reversible command using a GQuark to identify it.
2641 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2642 * but there must be as many begin...()s as there are commit...()s.
2645 Session::begin_reversible_command (GQuark q)
2647 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2648 to hold all the commands that are committed. This keeps the order of
2649 commands correct in the history.
2652 if (_current_trans == 0) {
2653 DEBUG_UNDO_HISTORY (string_compose (
2654 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2656 /* start a new transaction */
2657 assert (_current_trans_quarks.empty ());
2658 _current_trans = new UndoTransaction();
2659 _current_trans->set_name (g_quark_to_string (q));
2661 DEBUG_UNDO_HISTORY (
2662 string_compose ("Begin Reversible Command, current transaction: %1",
2663 _current_trans->name ()));
2666 _current_trans_quarks.push_front (q);
2670 Session::abort_reversible_command ()
2672 if (_current_trans != 0) {
2673 DEBUG_UNDO_HISTORY (
2674 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2675 _current_trans->clear();
2676 delete _current_trans;
2678 _current_trans_quarks.clear();
2683 Session::commit_reversible_command (Command *cmd)
2685 assert (_current_trans);
2686 assert (!_current_trans_quarks.empty ());
2691 DEBUG_UNDO_HISTORY (
2692 string_compose ("Current Undo Transaction %1, adding command: %2",
2693 _current_trans->name (),
2695 _current_trans->add_command (cmd);
2698 DEBUG_UNDO_HISTORY (
2699 string_compose ("Commit Reversible Command, current transaction: %1",
2700 _current_trans->name ()));
2702 _current_trans_quarks.pop_front ();
2704 if (!_current_trans_quarks.empty ()) {
2705 DEBUG_UNDO_HISTORY (
2706 string_compose ("Commit Reversible Command, transaction is not "
2707 "top-level, current transaction: %1",
2708 _current_trans->name ()));
2709 /* the transaction we're committing is not the top-level one */
2713 if (_current_trans->empty()) {
2714 /* no commands were added to the transaction, so just get rid of it */
2715 DEBUG_UNDO_HISTORY (
2716 string_compose ("Commit Reversible Command, No commands were "
2717 "added to current transaction: %1",
2718 _current_trans->name ()));
2719 delete _current_trans;
2724 gettimeofday (&now, 0);
2725 _current_trans->set_timestamp (now);
2727 _history.add (_current_trans);
2732 accept_all_audio_files (const string& path, void* /*arg*/)
2734 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2738 if (!AudioFileSource::safe_audio_file_extension (path)) {
2746 accept_all_midi_files (const string& path, void* /*arg*/)
2748 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2752 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2753 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2754 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2758 accept_all_state_files (const string& path, void* /*arg*/)
2760 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2764 std::string const statefile_ext (statefile_suffix);
2765 if (path.length() >= statefile_ext.length()) {
2766 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2773 Session::find_all_sources (string path, set<string>& result)
2778 if (!tree.read (path)) {
2782 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2787 XMLNodeConstIterator niter;
2789 nlist = node->children();
2793 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2797 if ((prop = (*niter)->property (X_("type"))) == 0) {
2801 DataType type (prop->value());
2803 if ((prop = (*niter)->property (X_("name"))) == 0) {
2807 if (Glib::path_is_absolute (prop->value())) {
2808 /* external file, ignore */
2816 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2817 result.insert (found_path);
2825 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2827 vector<string> state_files;
2829 string this_snapshot_path;
2835 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2836 ripped = ripped.substr (0, ripped.length() - 1);
2839 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2841 if (state_files.empty()) {
2846 this_snapshot_path = _path;
2847 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2848 this_snapshot_path += statefile_suffix;
2850 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2852 if (exclude_this_snapshot && *i == this_snapshot_path) {
2856 if (find_all_sources (*i, result) < 0) {
2864 struct RegionCounter {
2865 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2866 AudioSourceList::iterator iter;
2867 boost::shared_ptr<Region> region;
2870 RegionCounter() : count (0) {}
2874 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2876 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2877 return r.get_value_or (1);
2881 Session::cleanup_regions ()
2883 bool removed = false;
2884 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2886 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2888 uint32_t used = playlists->region_use_count (i->second);
2890 if (used == 0 && !i->second->automatic ()) {
2891 boost::weak_ptr<Region> w = i->second;
2894 RegionFactory::map_remove (w);
2901 // re-check to remove parent references of compound regions
2902 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2903 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2907 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2908 if (0 == playlists->region_use_count (i->second)) {
2909 boost::weak_ptr<Region> w = i->second;
2911 RegionFactory::map_remove (w);
2918 /* dump the history list */
2925 Session::can_cleanup_peakfiles () const
2927 if (deletion_in_progress()) {
2930 if (!_writable || (_state_of_the_state & CannotSave)) {
2931 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2934 if (record_status() == Recording) {
2935 error << _("Cannot cleanup peak-files while recording") << endmsg;
2942 Session::cleanup_peakfiles ()
2944 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2949 assert (can_cleanup_peakfiles ());
2950 assert (!peaks_cleanup_in_progres());
2952 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2954 int timeout = 5000; // 5 seconds
2955 while (!SourceFactory::files_with_peaks.empty()) {
2956 Glib::usleep (1000);
2957 if (--timeout < 0) {
2958 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2959 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2964 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2965 boost::shared_ptr<AudioSource> as;
2966 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2967 as->close_peakfile();
2971 PBD::clear_directory (session_directory().peak_path());
2973 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2975 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2976 boost::shared_ptr<AudioSource> as;
2977 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2978 SourceFactory::setup_peakfile(as, true);
2985 Session::cleanup_sources (CleanupReport& rep)
2987 // FIXME: needs adaptation to midi
2989 vector<boost::shared_ptr<Source> > dead_sources;
2992 vector<string> candidates;
2993 vector<string> unused;
2994 set<string> all_sources;
3003 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3005 /* this is mostly for windows which doesn't allow file
3006 * renaming if the file is in use. But we don't special
3007 * case it because we need to know if this causes
3008 * problems, and the easiest way to notice that is to
3009 * keep it in place for all platforms.
3012 request_stop (false);
3014 _butler->wait_until_finished ();
3016 /* consider deleting all unused playlists */
3018 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3023 /* sync the "all regions" property of each playlist with its current state
3026 playlists->sync_all_regions_with_regions ();
3028 /* find all un-used sources */
3033 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3035 SourceMap::iterator tmp;
3040 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3044 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3045 dead_sources.push_back (i->second);
3046 i->second->drop_references ();
3052 /* build a list of all the possible audio directories for the session */
3054 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3055 SessionDirectory sdir ((*i).path);
3056 asp += sdir.sound_path();
3058 audio_path += asp.to_string();
3061 /* build a list of all the possible midi directories for the session */
3063 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3064 SessionDirectory sdir ((*i).path);
3065 msp += sdir.midi_path();
3067 midi_path += msp.to_string();
3069 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3070 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3072 /* find all sources, but don't use this snapshot because the
3073 state file on disk still references sources we may have already
3077 find_all_sources_across_snapshots (all_sources, true);
3079 /* add our current source list
3082 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3083 boost::shared_ptr<FileSource> fs;
3084 SourceMap::iterator tmp = i;
3087 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3089 /* this is mostly for windows which doesn't allow file
3090 * renaming if the file is in use. But we don't special
3091 * case it because we need to know if this causes
3092 * problems, and the easiest way to notice that is to
3093 * keep it in place for all platforms.
3098 if (!fs->is_stub()) {
3100 if (playlists->source_use_count (fs) != 0) {
3101 all_sources.insert (fs->path());
3104 /* we might not remove this source from disk, because it may be used
3105 by other snapshots, but its not being used in this version
3106 so lets get rid of it now, along with any representative regions
3110 RegionFactory::remove_regions_using_source (i->second);
3112 // also remove source from all_sources
3114 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3115 spath = Glib::path_get_basename (*j);
3116 if (spath == i->second->name()) {
3117 all_sources.erase (j);
3130 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3135 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3137 tmppath1 = canonical_path (spath);
3138 tmppath2 = canonical_path ((*i));
3140 if (tmppath1 == tmppath2) {
3147 unused.push_back (spath);
3151 /* now try to move all unused files into the "dead" directory(ies) */
3153 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3158 /* don't move the file across filesystems, just
3159 stick it in the `dead_dir_name' directory
3160 on whichever filesystem it was already on.
3163 if ((*x).find ("/sounds/") != string::npos) {
3165 /* old school, go up 1 level */
3167 newpath = Glib::path_get_dirname (*x); // "sounds"
3168 newpath = Glib::path_get_dirname (newpath); // "session-name"
3172 /* new school, go up 4 levels */
3174 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3175 newpath = Glib::path_get_dirname (newpath); // "session-name"
3176 newpath = Glib::path_get_dirname (newpath); // "interchange"
3177 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3180 newpath = Glib::build_filename (newpath, dead_dir_name);
3182 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3183 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3187 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3189 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3191 /* the new path already exists, try versioning */
3193 char buf[PATH_MAX+1];
3197 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3200 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3201 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3205 if (version == 999) {
3206 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3210 newpath = newpath_v;
3215 /* it doesn't exist, or we can't read it or something */
3219 g_stat ((*x).c_str(), &statbuf);
3221 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3222 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3223 (*x), newpath, strerror (errno))
3228 /* see if there an easy to find peakfile for this file, and remove it.
3231 string base = Glib::path_get_basename (*x);
3232 base += "%A"; /* this is what we add for the channel suffix of all native files,
3233 or for the first channel of embedded files. it will miss
3234 some peakfiles for other channels
3236 string peakpath = construct_peak_filepath (base);
3238 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3239 if (::g_unlink (peakpath.c_str()) != 0) {
3240 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3241 peakpath, _path, strerror (errno))
3243 /* try to back out */
3244 ::rename (newpath.c_str(), _path.c_str());
3249 rep.paths.push_back (*x);
3250 rep.space += statbuf.st_size;
3253 /* dump the history list */
3257 /* save state so we don't end up a session file
3258 referring to non-existent sources.
3265 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3271 Session::cleanup_trash_sources (CleanupReport& rep)
3273 // FIXME: needs adaptation for MIDI
3275 vector<space_and_path>::iterator i;
3281 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3283 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3285 clear_directory (dead_dir, &rep.space, &rep.paths);
3292 Session::set_dirty ()
3294 /* never mark session dirty during loading */
3296 if (_state_of_the_state & Loading) {
3300 bool was_dirty = dirty();
3302 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3306 DirtyChanged(); /* EMIT SIGNAL */
3312 Session::set_clean ()
3314 bool was_dirty = dirty();
3316 _state_of_the_state = Clean;
3320 DirtyChanged(); /* EMIT SIGNAL */
3325 Session::set_deletion_in_progress ()
3327 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3331 Session::clear_deletion_in_progress ()
3333 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3337 Session::add_controllable (boost::shared_ptr<Controllable> c)
3339 /* this adds a controllable to the list managed by the Session.
3340 this is a subset of those managed by the Controllable class
3341 itself, and represents the only ones whose state will be saved
3342 as part of the session.
3345 Glib::Threads::Mutex::Lock lm (controllables_lock);
3346 controllables.insert (c);
3349 struct null_deleter { void operator()(void const *) const {} };
3352 Session::remove_controllable (Controllable* c)
3354 if (_state_of_the_state & Deletion) {
3358 Glib::Threads::Mutex::Lock lm (controllables_lock);
3360 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3362 if (x != controllables.end()) {
3363 controllables.erase (x);
3367 boost::shared_ptr<Controllable>
3368 Session::controllable_by_id (const PBD::ID& id)
3370 Glib::Threads::Mutex::Lock lm (controllables_lock);
3372 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3373 if ((*i)->id() == id) {
3378 return boost::shared_ptr<Controllable>();
3381 boost::shared_ptr<Controllable>
3382 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3384 boost::shared_ptr<Controllable> c;
3385 boost::shared_ptr<Route> r;
3387 switch (desc.top_level_type()) {
3388 case ControllableDescriptor::NamedRoute:
3390 std::string str = desc.top_level_name();
3391 if (str == "Master" || str == "master") {
3393 } else if (str == "control" || str == "listen") {
3396 r = route_by_name (desc.top_level_name());
3401 case ControllableDescriptor::RemoteControlID:
3402 r = route_by_remote_id (desc.rid());
3405 case ControllableDescriptor::SelectionCount:
3406 r = route_by_selected_count (desc.selection_id());
3414 switch (desc.subtype()) {
3415 case ControllableDescriptor::Gain:
3416 c = r->gain_control ();
3419 case ControllableDescriptor::Trim:
3420 c = r->trim()->gain_control ();
3423 case ControllableDescriptor::Solo:
3424 c = r->solo_control();
3427 case ControllableDescriptor::Mute:
3428 c = r->mute_control();
3431 case ControllableDescriptor::Recenable:
3433 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3436 c = t->rec_enable_control ();
3441 case ControllableDescriptor::PanDirection:
3442 c = r->pan_azimuth_control();
3445 case ControllableDescriptor::PanWidth:
3446 c = r->pan_width_control();
3449 case ControllableDescriptor::PanElevation:
3450 c = r->pan_elevation_control();
3453 case ControllableDescriptor::Balance:
3454 /* XXX simple pan control */
3457 case ControllableDescriptor::PluginParameter:
3459 uint32_t plugin = desc.target (0);
3460 uint32_t parameter_index = desc.target (1);
3462 /* revert to zero based counting */
3468 if (parameter_index > 0) {
3472 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3475 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3476 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3481 case ControllableDescriptor::SendGain: {
3482 uint32_t send = desc.target (0);
3486 c = r->send_level_controllable (send);
3491 /* relax and return a null pointer */
3499 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3502 Stateful::add_instant_xml (node, _path);
3505 if (write_to_config) {
3506 Config->add_instant_xml (node);
3511 Session::instant_xml (const string& node_name)
3513 return Stateful::instant_xml (node_name, _path);
3517 Session::save_history (string snapshot_name)
3525 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3526 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3530 if (snapshot_name.empty()) {
3531 snapshot_name = _current_snapshot_name;
3534 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3535 const string backup_filename = history_filename + backup_suffix;
3536 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3537 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3539 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3540 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3541 error << _("could not backup old history file, current history not saved") << endmsg;
3546 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3548 if (!tree.write (xml_path))
3550 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3552 if (g_remove (xml_path.c_str()) != 0) {
3553 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3554 xml_path, g_strerror (errno)) << endmsg;
3556 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3557 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3558 backup_path, g_strerror (errno)) << endmsg;
3568 Session::restore_history (string snapshot_name)
3572 if (snapshot_name.empty()) {
3573 snapshot_name = _current_snapshot_name;
3576 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3577 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3579 info << "Loading history from " << xml_path << endmsg;
3581 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3582 info << string_compose (_("%1: no history file \"%2\" for this session."),
3583 _name, xml_path) << endmsg;
3587 if (!tree.read (xml_path)) {
3588 error << string_compose (_("Could not understand session history file \"%1\""),
3589 xml_path) << endmsg;
3596 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3599 UndoTransaction* ut = new UndoTransaction ();
3602 ut->set_name(t->property("name")->value());
3603 stringstream ss(t->property("tv-sec")->value());
3605 ss.str(t->property("tv-usec")->value());
3607 ut->set_timestamp(tv);
3609 for (XMLNodeConstIterator child_it = t->children().begin();
3610 child_it != t->children().end(); child_it++)
3612 XMLNode *n = *child_it;
3615 if (n->name() == "MementoCommand" ||
3616 n->name() == "MementoUndoCommand" ||
3617 n->name() == "MementoRedoCommand") {
3619 if ((c = memento_command_factory(n))) {
3623 } else if (n->name() == "NoteDiffCommand") {
3624 PBD::ID id (n->property("midi-source")->value());
3625 boost::shared_ptr<MidiSource> midi_source =
3626 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3628 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3630 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3633 } else if (n->name() == "SysExDiffCommand") {
3635 PBD::ID id (n->property("midi-source")->value());
3636 boost::shared_ptr<MidiSource> midi_source =
3637 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3639 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3641 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3644 } else if (n->name() == "PatchChangeDiffCommand") {
3646 PBD::ID id (n->property("midi-source")->value());
3647 boost::shared_ptr<MidiSource> midi_source =
3648 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3650 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3652 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3655 } else if (n->name() == "StatefulDiffCommand") {
3656 if ((c = stateful_diff_command_factory (n))) {
3657 ut->add_command (c);
3660 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3671 Session::config_changed (std::string p, bool ours)
3677 if (p == "seamless-loop") {
3679 } else if (p == "rf-speed") {
3681 } else if (p == "auto-loop") {
3683 } else if (p == "auto-input") {
3685 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3686 /* auto-input only makes a difference if we're rolling */
3687 set_track_monitor_input_status (!config.get_auto_input());
3690 } else if (p == "punch-in") {
3694 if ((location = _locations->auto_punch_location()) != 0) {
3696 if (config.get_punch_in ()) {
3697 replace_event (SessionEvent::PunchIn, location->start());
3699 remove_event (location->start(), SessionEvent::PunchIn);
3703 } else if (p == "punch-out") {
3707 if ((location = _locations->auto_punch_location()) != 0) {
3709 if (config.get_punch_out()) {
3710 replace_event (SessionEvent::PunchOut, location->end());
3712 clear_events (SessionEvent::PunchOut);
3716 } else if (p == "edit-mode") {
3718 Glib::Threads::Mutex::Lock lm (playlists->lock);
3720 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3721 (*i)->set_edit_mode (Config->get_edit_mode ());
3724 } else if (p == "use-video-sync") {
3726 waiting_for_sync_offset = config.get_use_video_sync();
3728 } else if (p == "mmc-control") {
3730 //poke_midi_thread ();
3732 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3734 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3736 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3738 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3740 } else if (p == "midi-control") {
3742 //poke_midi_thread ();
3744 } else if (p == "raid-path") {
3746 setup_raid_path (config.get_raid_path());
3748 } else if (p == "timecode-format") {
3752 } else if (p == "video-pullup") {
3756 } else if (p == "seamless-loop") {
3758 if (play_loop && transport_rolling()) {
3759 // to reset diskstreams etc
3760 request_play_loop (true);
3763 } else if (p == "rf-speed") {
3765 cumulative_rf_motion = 0;
3768 } else if (p == "click-sound") {
3770 setup_click_sounds (1);
3772 } else if (p == "click-emphasis-sound") {
3774 setup_click_sounds (-1);
3776 } else if (p == "clicking") {
3778 if (Config->get_clicking()) {
3779 if (_click_io && click_data) { // don't require emphasis data
3786 } else if (p == "click-gain") {
3789 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3792 } else if (p == "send-mtc") {
3794 if (Config->get_send_mtc ()) {
3795 /* mark us ready to send */
3796 next_quarter_frame_to_send = 0;
3799 } else if (p == "send-mmc") {
3801 _mmc->enable_send (Config->get_send_mmc ());
3803 } else if (p == "midi-feedback") {
3805 session_midi_feedback = Config->get_midi_feedback();
3807 } else if (p == "jack-time-master") {
3809 engine().reset_timebase ();
3811 } else if (p == "native-file-header-format") {
3813 if (!first_file_header_format_reset) {
3814 reset_native_file_format ();
3817 first_file_header_format_reset = false;
3819 } else if (p == "native-file-data-format") {
3821 if (!first_file_data_format_reset) {
3822 reset_native_file_format ();
3825 first_file_data_format_reset = false;
3827 } else if (p == "external-sync") {
3828 if (!config.get_external_sync()) {
3829 drop_sync_source ();
3831 switch_to_sync_source (Config->get_sync_source());
3833 } else if (p == "denormal-model") {
3835 } else if (p == "history-depth") {
3836 set_history_depth (Config->get_history_depth());
3837 } else if (p == "remote-model") {
3838 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3841 } else if (p == "initial-program-change") {
3843 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3846 buf[0] = MIDI::program; // channel zero by default
3847 buf[1] = (Config->get_initial_program_change() & 0x7f);
3849 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3851 } else if (p == "solo-mute-override") {
3852 // catch_up_on_solo_mute_override ();
3853 } else if (p == "listen-position" || p == "pfl-position") {
3854 listen_position_changed ();
3855 } else if (p == "solo-control-is-listen-control") {
3856 solo_control_mode_changed ();
3857 } else if (p == "solo-mute-gain") {
3858 _solo_cut_control->Changed();
3859 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3860 last_timecode_valid = false;
3861 } else if (p == "playback-buffer-seconds") {
3862 AudioSource::allocate_working_buffers (frame_rate());
3863 } else if (p == "ltc-source-port") {
3864 reconnect_ltc_input ();
3865 } else if (p == "ltc-sink-port") {
3866 reconnect_ltc_output ();
3867 } else if (p == "timecode-generator-offset") {
3868 ltc_tx_parse_offset();
3869 } else if (p == "auto-return-target-list") {
3870 follow_playhead_priority ();
3877 Session::set_history_depth (uint32_t d)
3879 _history.set_depth (d);
3883 Session::load_diskstreams_2X (XMLNode const & node, int)
3886 XMLNodeConstIterator citer;
3888 clist = node.children();
3890 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3893 /* diskstreams added automatically by DiskstreamCreated handler */
3894 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3895 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3896 _diskstreams_2X.push_back (dsp);
3898 error << _("Session: unknown diskstream type in XML") << endmsg;
3902 catch (failed_constructor& err) {
3903 error << _("Session: could not load diskstream via XML state") << endmsg;
3911 /** Connect things to the MMC object */
3913 Session::setup_midi_machine_control ()
3915 _mmc = new MIDI::MachineControl;
3917 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
3918 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
3920 if (!async_out || !async_out) {
3924 /* XXXX argh, passing raw pointers back into libmidi++ */
3926 MIDI::Port* mmc_in = async_in.get();
3927 MIDI::Port* mmc_out = async_out.get();
3929 _mmc->set_ports (mmc_in, mmc_out);
3931 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3932 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3933 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3934 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3935 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3936 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3937 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3938 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3939 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3940 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3941 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3942 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3943 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3945 /* also handle MIDI SPP because its so common */
3947 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3948 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3949 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3952 boost::shared_ptr<Controllable>
3953 Session::solo_cut_control() const
3955 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3956 controls in Ardour that currently get presented to the user in the GUI that require
3957 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3959 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3960 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3964 return _solo_cut_control;
3968 Session::save_snapshot_name (const std::string & n)
3970 /* assure Stateful::_instant_xml is loaded
3971 * add_instant_xml() only adds to existing data and defaults
3972 * to use an empty Tree otherwise
3974 instant_xml ("LastUsedSnapshot");
3976 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
3977 last_used_snapshot->add_property ("name", string(n));
3978 add_instant_xml (*last_used_snapshot, false);
3982 Session::set_snapshot_name (const std::string & n)
3984 _current_snapshot_name = n;
3985 save_snapshot_name (n);
3989 Session::rename (const std::string& new_name)
3991 string legal_name = legalize_for_path (new_name);
3997 string const old_sources_root = _session_dir->sources_root();
3999 if (!_writable || (_state_of_the_state & CannotSave)) {
4000 error << _("Cannot rename read-only session.") << endmsg;
4001 return 0; // don't show "messed up" warning
4003 if (record_status() == Recording) {
4004 error << _("Cannot rename session while recording") << endmsg;
4005 return 0; // don't show "messed up" warning
4008 StateProtector stp (this);
4013 * interchange subdirectory
4017 * Backup files are left unchanged and not renamed.
4020 /* Windows requires that we close all files before attempting the
4021 * rename. This works on other platforms, but isn't necessary there.
4022 * Leave it in place for all platforms though, since it may help
4023 * catch issues that could arise if the way Source files work ever
4024 * change (since most developers are not using Windows).
4027 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4028 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4034 /* pass one: not 100% safe check that the new directory names don't
4038 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4042 /* this is a stupid hack because Glib::path_get_dirname() is
4043 * lexical-only, and so passing it /a/b/c/ gives a different
4044 * result than passing it /a/b/c ...
4047 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4048 oldstr = oldstr.substr (0, oldstr.length() - 1);
4051 string base = Glib::path_get_dirname (oldstr);
4053 newstr = Glib::build_filename (base, legal_name);
4055 cerr << "Looking for " << newstr << endl;
4057 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4058 cerr << " exists\n";
4067 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4073 /* this is a stupid hack because Glib::path_get_dirname() is
4074 * lexical-only, and so passing it /a/b/c/ gives a different
4075 * result than passing it /a/b/c ...
4078 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4079 oldstr = oldstr.substr (0, oldstr.length() - 1);
4082 string base = Glib::path_get_dirname (oldstr);
4083 newstr = Glib::build_filename (base, legal_name);
4085 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4087 cerr << "Rename " << oldstr << " => " << newstr << endl;
4088 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4089 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4090 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4094 /* Reset path in "session dirs" */
4099 /* reset primary SessionDirectory object */
4102 (*_session_dir) = newstr;
4107 /* now rename directory below session_dir/interchange */
4109 string old_interchange_dir;
4110 string new_interchange_dir;
4112 /* use newstr here because we renamed the path
4113 * (folder/directory) that used to be oldstr to newstr above
4116 v.push_back (newstr);
4117 v.push_back (interchange_dir_name);
4118 v.push_back (Glib::path_get_basename (oldstr));
4120 old_interchange_dir = Glib::build_filename (v);
4123 v.push_back (newstr);
4124 v.push_back (interchange_dir_name);
4125 v.push_back (legal_name);
4127 new_interchange_dir = Glib::build_filename (v);
4129 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4131 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4132 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4133 old_interchange_dir, new_interchange_dir,
4136 error << string_compose (_("renaming %s as %2 failed (%3)"),
4137 old_interchange_dir, new_interchange_dir,
4146 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4147 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4149 cerr << "Rename " << oldstr << " => " << newstr << endl;
4151 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4152 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4153 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4159 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4161 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4162 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4164 cerr << "Rename " << oldstr << " => " << newstr << endl;
4166 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4167 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4168 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4173 /* remove old name from recent sessions */
4174 remove_recent_sessions (_path);
4177 /* update file source paths */
4179 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4180 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4182 string p = fs->path ();
4183 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4185 SourceFactory::setup_peakfile(i->second, true);
4189 set_snapshot_name (new_name);
4194 /* save state again to get everything just right */
4196 save_state (_current_snapshot_name);
4198 /* add to recent sessions */
4200 store_recent_sessions (new_name, _path);
4206 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4208 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4212 if (!tree.read (xmlpath)) {
4220 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4223 bool found_sr = false;
4224 bool found_data_format = false;
4226 if (get_session_info_from_path (tree, xmlpath)) {
4232 const XMLProperty* prop;
4233 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4234 sample_rate = atoi (prop->value());
4238 const XMLNodeList& children (tree.root()->children());
4239 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4240 const XMLNode* child = *c;
4241 if (child->name() == "Config") {
4242 const XMLNodeList& options (child->children());
4243 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4244 const XMLNode* option = *oc;
4245 const XMLProperty* name = option->property("name");
4251 if (name->value() == "native-file-data-format") {
4252 const XMLProperty* value = option->property ("value");
4254 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4256 found_data_format = true;
4262 if (found_data_format) {
4267 return !(found_sr && found_data_format); // zero if they are both found
4271 Session::get_snapshot_from_instant (const std::string& session_dir)
4273 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4275 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4280 if (!tree.read (instant_xml_path)) {
4284 const XMLProperty* prop;
4285 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4286 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4287 return prop->value();
4293 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4294 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4297 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4301 SourcePathMap source_path_map;
4303 boost::shared_ptr<AudioFileSource> afs;
4308 Glib::Threads::Mutex::Lock lm (source_lock);
4310 cerr << " total sources = " << sources.size();
4312 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4313 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4319 if (fs->within_session()) {
4323 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4324 source_path_map[fs->path()].push_back (fs);
4326 SeveralFileSources v;
4328 source_path_map.insert (make_pair (fs->path(), v));
4334 cerr << " fsources = " << total << endl;
4336 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4338 /* tell caller where we are */
4340 string old_path = i->first;
4342 callback (n, total, old_path);
4344 cerr << old_path << endl;
4348 switch (i->second.front()->type()) {
4349 case DataType::AUDIO:
4350 new_path = new_audio_source_path_for_embedded (old_path);
4353 case DataType::MIDI:
4354 /* XXX not implemented yet */
4358 if (new_path.empty()) {
4362 cerr << "Move " << old_path << " => " << new_path << endl;
4364 if (!copy_file (old_path, new_path)) {
4365 cerr << "failed !\n";
4369 /* make sure we stop looking in the external
4370 dir/folder. Remember, this is an all-or-nothing
4371 operations, it doesn't merge just some files.
4373 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4375 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4376 (*f)->set_path (new_path);
4381 save_state ("", false, false);
4387 bool accept_all_files (string const &, void *)
4393 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4395 /* 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.
4400 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4402 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4404 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4406 v.push_back (new_session_folder); /* full path */
4407 v.push_back (interchange_dir_name);
4408 v.push_back (new_session_path); /* just one directory/folder */
4409 v.push_back (typedir);
4410 v.push_back (Glib::path_get_basename (old_path));
4412 return Glib::build_filename (v);
4416 Session::save_as (SaveAs& saveas)
4418 vector<string> files;
4419 string current_folder = Glib::path_get_dirname (_path);
4420 string new_folder = legalize_for_path (saveas.new_name);
4421 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4422 int64_t total_bytes = 0;
4426 int32_t internal_file_cnt = 0;
4428 vector<string> do_not_copy_extensions;
4429 do_not_copy_extensions.push_back (statefile_suffix);
4430 do_not_copy_extensions.push_back (pending_suffix);
4431 do_not_copy_extensions.push_back (backup_suffix);
4432 do_not_copy_extensions.push_back (temp_suffix);
4433 do_not_copy_extensions.push_back (history_suffix);
4435 /* get total size */
4437 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4439 /* need to clear this because
4440 * find_files_matching_filter() is cumulative
4445 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4447 all += files.size();
4449 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4451 g_stat ((*i).c_str(), &gsb);
4452 total_bytes += gsb.st_size;
4456 /* save old values so we can switch back if we are not switching to the new session */
4458 string old_path = _path;
4459 string old_name = _name;
4460 string old_snapshot = _current_snapshot_name;
4461 string old_sd = _session_dir->root_path();
4462 vector<string> old_search_path[DataType::num_types];
4463 string old_config_search_path[DataType::num_types];
4465 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4466 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4467 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4468 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4470 /* switch session directory */
4472 (*_session_dir) = to_dir;
4474 /* create new tree */
4476 if (!_session_dir->create()) {
4477 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4482 /* copy all relevant files. Find each location in session_dirs,
4483 * and copy files from there to target.
4486 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4488 /* need to clear this because
4489 * find_files_matching_filter() is cumulative
4494 const size_t prefix_len = (*sd).path.size();
4496 /* Work just on the files within this session dir */
4498 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4500 /* add dir separator to protect against collisions with
4501 * track names (e.g. track named "audiofiles" or
4505 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4506 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4507 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4509 /* copy all the files. Handling is different for media files
4510 than others because of the *silly* subtree we have below the interchange
4511 folder. That really was a bad idea, but I'm not fixing it as part of
4512 implementing ::save_as().
4515 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4517 std::string from = *i;
4520 string filename = Glib::path_get_basename (from);
4521 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4522 if (filename == ".DS_STORE") {
4527 if (from.find (audiofile_dir_string) != string::npos) {
4529 /* audio file: only copy if asked */
4531 if (saveas.include_media && saveas.copy_media) {
4533 string to = make_new_media_path (*i, to_dir, new_folder);
4535 info << "media file copying from " << from << " to " << to << endmsg;
4537 if (!copy_file (from, to)) {
4538 throw Glib::FileError (Glib::FileError::IO_ERROR,
4539 string_compose(_("\ncopying \"%1\" failed !"), from));
4543 /* we found media files inside the session folder */
4545 internal_file_cnt++;
4547 } else if (from.find (midifile_dir_string) != string::npos) {
4549 /* midi file: always copy unless
4550 * creating an empty new session
4553 if (saveas.include_media) {
4555 string to = make_new_media_path (*i, to_dir, new_folder);
4557 info << "media file copying from " << from << " to " << to << endmsg;
4559 if (!copy_file (from, to)) {
4560 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4564 /* we found media files inside the session folder */
4566 internal_file_cnt++;
4568 } else if (from.find (analysis_dir_string) != string::npos) {
4570 /* make sure analysis dir exists in
4571 * new session folder, but we're not
4572 * copying analysis files here, see
4576 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4581 /* normal non-media file. Don't copy state, history, etc.
4584 bool do_copy = true;
4586 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4587 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4588 /* end of filename matches extension, do not copy file */
4594 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4595 /* don't copy peakfiles if
4596 * we're not copying media
4602 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4604 info << "attempting to make directory/folder " << to << endmsg;
4606 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4607 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4610 info << "attempting to copy " << from << " to " << to << endmsg;
4612 if (!copy_file (from, to)) {
4613 throw Glib::FileError (Glib::FileError::IO_ERROR,
4614 string_compose(_("\ncopying \"%1\" failed !"), from));
4619 /* measure file size even if we're not going to copy so that our Progress
4620 signals are correct, since we included these do-not-copy files
4621 in the computation of the total size and file count.
4625 g_stat (from.c_str(), &gsb);
4626 copied += gsb.st_size;
4629 double fraction = (double) copied / total_bytes;
4631 bool keep_going = true;
4633 if (saveas.copy_media) {
4635 /* no need or expectation of this if
4636 * media is not being copied, because
4637 * it will be fast(ish).
4640 /* tell someone "X percent, file M of N"; M is one-based */
4642 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4650 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4656 /* copy optional folders, if any */
4658 string old = plugins_dir ();
4659 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4660 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4661 copy_files (old, newdir);
4664 old = externals_dir ();
4665 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4666 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4667 copy_files (old, newdir);
4670 old = automation_dir ();
4671 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4672 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4673 copy_files (old, newdir);
4676 if (saveas.include_media) {
4678 if (saveas.copy_media) {
4679 #ifndef PLATFORM_WINDOWS
4680 /* There are problems with analysis files on
4681 * Windows, because they used a colon in their
4682 * names as late as 4.0. Colons are not legal
4683 * under Windows even if NTFS allows them.
4685 * This is a tricky problem to solve so for
4686 * just don't copy these files. They will be
4687 * regenerated as-needed anyway, subject to the
4688 * existing issue that the filenames will be
4689 * rejected by Windows, which is a separate
4690 * problem (though related).
4693 /* only needed if we are copying media, since the
4694 * analysis data refers to media data
4697 old = analysis_dir ();
4698 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4699 string newdir = Glib::build_filename (to_dir, "analysis");
4700 copy_files (old, newdir);
4702 #endif /* PLATFORM_WINDOWS */
4708 set_snapshot_name (saveas.new_name);
4709 _name = saveas.new_name;
4711 if (saveas.include_media && !saveas.copy_media) {
4713 /* reset search paths of the new session (which we're pretending to be right now) to
4714 include the original session search path, so we can still find all audio.
4717 if (internal_file_cnt) {
4718 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4719 ensure_search_path_includes (*s, DataType::AUDIO);
4720 cerr << "be sure to include " << *s << " for audio" << endl;
4723 /* we do not do this for MIDI because we copy
4724 all MIDI files if saveas.include_media is
4730 bool was_dirty = dirty ();
4732 save_state ("", false, false, !saveas.include_media);
4733 save_default_options ();
4735 if (saveas.copy_media && saveas.copy_external) {
4736 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4737 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4741 saveas.final_session_folder_name = _path;
4743 store_recent_sessions (_name, _path);
4745 if (!saveas.switch_to) {
4747 /* switch back to the way things were */
4751 set_snapshot_name (old_snapshot);
4753 (*_session_dir) = old_sd;
4759 if (internal_file_cnt) {
4760 /* reset these to their original values */
4761 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4762 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4767 /* prune session dirs, and update disk space statistics
4772 session_dirs.clear ();
4773 session_dirs.push_back (sp);
4774 refresh_disk_space ();
4776 /* ensure that all existing tracks reset their current capture source paths
4778 reset_write_sources (true, true);
4780 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4781 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4784 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4785 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4791 if (fs->within_session()) {
4792 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4793 fs->set_path (newpath);
4798 } catch (Glib::FileError& e) {
4800 saveas.failure_message = e.what();
4802 /* recursively remove all the directories */
4804 remove_directory (to_dir);
4812 saveas.failure_message = _("unknown reason");
4814 /* recursively remove all the directories */
4816 remove_directory (to_dir);