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 */
255 midi_clock = new MidiClockTicker ();
256 midi_clock->set_session (this);
258 /* crossfades require sample rate knowledge */
260 SndFileSource::setup_standard_crossfades (*this, frame_rate());
261 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
263 AudioDiskstream::allocate_working_buffers();
264 refresh_disk_space ();
266 /* we're finally ready to call set_state() ... all objects have
267 * been created, the engine is running.
271 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
275 // set_state() will call setup_raid_path(), but if it's a new session we need
276 // to call setup_raid_path() here.
277 setup_raid_path (_path);
282 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
283 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
285 Config->map_parameters (ff);
286 config.map_parameters (ft);
287 _butler->map_parameters ();
289 /* Reset all panners */
291 Delivery::reset_panners ();
293 /* this will cause the CPM to instantiate any protocols that are in use
294 * (or mandatory), which will pass it this Session, and then call
295 * set_state() on each instantiated protocol to match stored state.
298 ControlProtocolManager::instance().set_session (this);
300 /* This must be done after the ControlProtocolManager set_session above,
301 as it will set states for ports which the ControlProtocolManager creates.
304 // XXX set state of MIDI::Port's
305 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
307 /* And this must be done after the MIDI::Manager::set_port_states as
308 * it will try to make connections whose details are loaded by set_port_states.
313 /* Let control protocols know that we are now all connected, so they
314 * could start talking to surfaces if they want to.
317 ControlProtocolManager::instance().midi_connectivity_established ();
319 if (_is_new && !no_auto_connect()) {
320 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
321 auto_connect_master_bus ();
324 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
326 /* update latencies */
328 initialize_latencies ();
330 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
331 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
332 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
334 } catch (AudioEngine::PortRegistrationFailure& err) {
335 /* handle this one in a different way than all others, so that its clear what happened */
336 error << err.what() << endmsg;
342 BootMessage (_("Reset Remote Controls"));
344 // send_full_time_code (0);
345 _engine.transport_locate (0);
347 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
348 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
350 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
353 /* initial program change will be delivered later; see ::config_changed() */
355 _state_of_the_state = Clean;
357 Port::set_connecting_blocked (false);
359 DirtyChanged (); /* EMIT SIGNAL */
363 } else if (state_was_pending) {
365 remove_pending_capture_state ();
366 state_was_pending = false;
369 /* Now, finally, we can fill the playback buffers */
371 BootMessage (_("Filling playback buffers"));
373 boost::shared_ptr<RouteList> rl = routes.reader();
374 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
375 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
376 if (trk && !trk->hidden()) {
377 trk->seek (_transport_frame, true);
385 Session::session_loaded ()
389 _state_of_the_state = Clean;
391 DirtyChanged (); /* EMIT SIGNAL */
395 } else if (state_was_pending) {
397 remove_pending_capture_state ();
398 state_was_pending = false;
401 /* Now, finally, we can fill the playback buffers */
403 BootMessage (_("Filling playback buffers"));
404 force_locate (_transport_frame, false);
408 Session::raid_path () const
410 Searchpath raid_search_path;
412 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
413 raid_search_path += (*i).path;
416 return raid_search_path.to_string ();
420 Session::setup_raid_path (string path)
429 session_dirs.clear ();
431 Searchpath search_path(path);
432 Searchpath sound_search_path;
433 Searchpath midi_search_path;
435 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
437 sp.blocks = 0; // not needed
438 session_dirs.push_back (sp);
440 SessionDirectory sdir(sp.path);
442 sound_search_path += sdir.sound_path ();
443 midi_search_path += sdir.midi_path ();
446 // reset the round-robin soundfile path thingie
447 last_rr_session_dir = session_dirs.begin();
451 Session::path_is_within_session (const std::string& path)
453 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
454 if (PBD::path_is_within (i->path, path)) {
462 Session::ensure_subdirs ()
466 dir = session_directory().peak_path();
468 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
469 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
473 dir = session_directory().sound_path();
475 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
476 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
480 dir = session_directory().midi_path();
482 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
483 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
487 dir = session_directory().dead_path();
489 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
490 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
494 dir = session_directory().export_path();
496 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
497 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
501 dir = analysis_dir ();
503 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
504 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
508 dir = plugins_dir ();
510 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
511 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
515 dir = externals_dir ();
517 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
518 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
525 /** @param session_template directory containing session template, or empty.
526 * Caller must not hold process lock.
529 Session::create (const string& session_template, BusProfile* bus_profile)
531 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
532 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
536 if (ensure_subdirs ()) {
540 _writable = exists_and_writable (_path);
542 if (!session_template.empty()) {
543 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
545 FILE* in = g_fopen (in_path.c_str(), "rb");
548 /* no need to call legalize_for_path() since the string
549 * in session_template is already a legal path name
551 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
553 FILE* out = g_fopen (out_path.c_str(), "wb");
557 stringstream new_session;
560 size_t charsRead = fread (buf, sizeof(char), 1024, in);
563 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
568 if (charsRead == 0) {
571 new_session.write (buf, charsRead);
575 string file_contents = new_session.str();
576 size_t writeSize = file_contents.length();
577 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
578 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
586 if (!ARDOUR::Profile->get_trx()) {
587 /* Copy plugin state files from template to new session */
588 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
589 copy_recurse (template_plugins, plugins_dir ());
595 error << string_compose (_("Could not open %1 for writing session template"), out_path)
602 error << string_compose (_("Could not open session template %1 for reading"), in_path)
609 if (Profile->get_trx()) {
611 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
612 Remember that this is a brand new session. Sessions
613 loaded from saved state will get this range from the saved state.
616 set_session_range_location (0, 0);
618 /* Initial loop location, from absolute zero, length 10 seconds */
620 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
621 _locations->add (loc, true);
622 set_auto_loop_location (loc);
625 _state_of_the_state = Clean;
627 /* set up Master Out and Control Out if necessary */
632 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
634 // Waves Tracks: always create master bus for Tracks
635 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
636 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
640 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
641 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
644 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
645 r->input()->ensure_io (count, false, this);
646 r->output()->ensure_io (count, false, this);
652 /* prohibit auto-connect to master, because there isn't one */
653 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
657 add_routes (rl, false, false, false);
660 // Waves Tracks: Skip this. Always use autoconnection for Tracks
661 if (!ARDOUR::Profile->get_trx()) {
663 /* this allows the user to override settings with an environment variable.
666 if (no_auto_connect()) {
667 bus_profile->input_ac = AutoConnectOption (0);
668 bus_profile->output_ac = AutoConnectOption (0);
671 Config->set_input_auto_connect (bus_profile->input_ac);
672 Config->set_output_auto_connect (bus_profile->output_ac);
676 if (Config->get_use_monitor_bus() && bus_profile) {
677 add_monitor_section ();
684 Session::maybe_write_autosave()
686 if (dirty() && record_status() != Recording) {
687 save_state("", true);
692 Session::remove_pending_capture_state ()
694 std::string pending_state_file_path(_session_dir->root_path());
696 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
698 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
700 if (g_remove (pending_state_file_path.c_str()) != 0) {
701 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
702 pending_state_file_path, g_strerror (errno)) << endmsg;
706 /** Rename a state file.
707 * @param old_name Old snapshot name.
708 * @param new_name New snapshot name.
711 Session::rename_state (string old_name, string new_name)
713 if (old_name == _current_snapshot_name || old_name == _name) {
714 /* refuse to rename the current snapshot or the "main" one */
718 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
719 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
721 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
722 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
724 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
725 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
726 old_name, new_name, g_strerror(errno)) << endmsg;
730 /** Remove a state file.
731 * @param snapshot_name Snapshot name.
734 Session::remove_state (string snapshot_name)
736 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
737 // refuse to remove the current snapshot or the "main" one
741 std::string xml_path(_session_dir->root_path());
743 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
745 if (!create_backup_file (xml_path)) {
746 // don't remove it if a backup can't be made
747 // create_backup_file will log the error.
752 if (g_remove (xml_path.c_str()) != 0) {
753 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
754 xml_path, g_strerror (errno)) << endmsg;
758 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
760 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
762 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
765 std::string xml_path(_session_dir->root_path());
767 /* prevent concurrent saves from different threads */
769 Glib::Threads::Mutex::Lock lm (save_state_lock);
771 if (!_writable || (_state_of_the_state & CannotSave)) {
775 if (g_atomic_int_get(&_suspend_save)) {
779 _save_queued = false;
781 if (!_engine.connected ()) {
782 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
789 const int64_t save_start_time = g_get_monotonic_time();
792 /* tell sources we're saving first, in case they write out to a new file
793 * which should be saved with the state rather than the old one */
794 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
796 i->second->session_saved();
797 } catch (Evoral::SMF::FileError& e) {
798 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
802 SessionSaveUnderway (); /* EMIT SIGNAL */
804 bool mark_as_clean = true;
806 if (!snapshot_name.empty() && !switch_to_snapshot) {
807 mark_as_clean = false;
811 mark_as_clean = false;
812 tree.set_root (&get_template());
814 tree.set_root (&get_state());
817 if (snapshot_name.empty()) {
818 snapshot_name = _current_snapshot_name;
819 } else if (switch_to_snapshot) {
820 set_snapshot_name (snapshot_name);
823 assert (!snapshot_name.empty());
827 /* proper save: use statefile_suffix (.ardour in English) */
829 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
831 /* make a backup copy of the old file */
833 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
834 // create_backup_file will log the error
840 /* pending save: use pending_suffix (.pending in English) */
841 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
844 std::string tmp_path(_session_dir->root_path());
845 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
847 cerr << "actually writing state to " << tmp_path << endl;
849 if (!tree.write (tmp_path)) {
850 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
851 if (g_remove (tmp_path.c_str()) != 0) {
852 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
853 tmp_path, g_strerror (errno)) << endmsg;
859 cerr << "renaming state to " << xml_path << endl;
861 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
862 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
863 tmp_path, xml_path, g_strerror(errno)) << endmsg;
864 if (g_remove (tmp_path.c_str()) != 0) {
865 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
866 tmp_path, g_strerror (errno)) << endmsg;
874 save_history (snapshot_name);
877 bool was_dirty = dirty();
879 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
882 DirtyChanged (); /* EMIT SIGNAL */
886 StateSaved (snapshot_name); /* EMIT SIGNAL */
890 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
891 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
897 Session::restore_state (string snapshot_name)
899 if (load_state (snapshot_name) == 0) {
900 set_state (*state_tree->root(), Stateful::loading_state_version);
907 Session::load_state (string snapshot_name)
912 state_was_pending = false;
914 /* check for leftover pending state from a crashed capture attempt */
916 std::string xmlpath(_session_dir->root_path());
917 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
919 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
921 /* there is pending state from a crashed capture attempt */
923 boost::optional<int> r = AskAboutPendingState();
924 if (r.get_value_or (1)) {
925 state_was_pending = true;
929 if (!state_was_pending) {
930 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
933 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
934 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
935 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
936 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
941 state_tree = new XMLTree;
945 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
947 if (!state_tree->read (xmlpath)) {
948 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
954 XMLNode const & root (*state_tree->root());
956 if (root.name() != X_("Session")) {
957 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
963 XMLProperty const * prop;
965 if ((prop = root.property ("version")) == 0) {
966 /* no version implies very old version of Ardour */
967 Stateful::loading_state_version = 1000;
969 if (prop->value().find ('.') != string::npos) {
970 /* old school version format */
971 if (prop->value()[0] == '2') {
972 Stateful::loading_state_version = 2000;
974 Stateful::loading_state_version = 3000;
977 Stateful::loading_state_version = atoi (prop->value());
981 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
983 std::string backup_path(_session_dir->root_path());
984 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
985 backup_path = Glib::build_filename (backup_path, backup_filename);
987 // only create a backup for a given statefile version once
989 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
991 VersionMismatch (xmlpath, backup_path);
993 if (!copy_file (xmlpath, backup_path)) {;
999 save_snapshot_name (snapshot_name);
1005 Session::load_options (const XMLNode& node)
1008 config.set_variables (node);
1013 Session::save_default_options ()
1015 return config.save_state();
1019 Session::get_state()
1025 Session::get_template()
1027 /* if we don't disable rec-enable, diskstreams
1028 will believe they need to store their capture
1029 sources in their state node.
1032 disable_record (false);
1034 return state(false);
1038 Session::state (bool full_state)
1041 XMLNode* node = new XMLNode("Session");
1045 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1046 node->add_property("version", buf);
1048 /* store configuration settings */
1052 node->add_property ("name", _name);
1053 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1054 node->add_property ("sample-rate", buf);
1056 if (session_dirs.size() > 1) {
1060 vector<space_and_path>::iterator i = session_dirs.begin();
1061 vector<space_and_path>::iterator next;
1063 ++i; /* skip the first one */
1067 while (i != session_dirs.end()) {
1071 if (next != session_dirs.end()) {
1072 p += G_SEARCHPATH_SEPARATOR;
1081 child = node->add_child ("Path");
1082 child->add_content (p);
1086 /* save the ID counter */
1088 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1089 node->add_property ("id-counter", buf);
1091 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1092 node->add_property ("name-counter", buf);
1094 /* save the event ID counter */
1096 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1097 node->add_property ("event-counter", buf);
1099 /* various options */
1101 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1102 if (!midi_port_nodes.empty()) {
1103 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1104 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1105 midi_port_stuff->add_child_nocopy (**n);
1107 node->add_child_nocopy (*midi_port_stuff);
1110 node->add_child_nocopy (config.get_variables ());
1112 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1114 child = node->add_child ("Sources");
1117 Glib::Threads::Mutex::Lock sl (source_lock);
1119 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1121 /* Don't save information about non-file Sources, or
1122 * about non-destructive file sources that are empty
1123 * and unused by any regions.
1126 boost::shared_ptr<FileSource> fs;
1128 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1130 if (!fs->destructive()) {
1131 if (fs->empty() && !fs->used()) {
1136 child->add_child_nocopy (siter->second->get_state());
1141 child = node->add_child ("Regions");
1144 Glib::Threads::Mutex::Lock rl (region_lock);
1145 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1146 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1147 boost::shared_ptr<Region> r = i->second;
1148 /* only store regions not attached to playlists */
1149 if (r->playlist() == 0) {
1150 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1151 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1153 child->add_child_nocopy (r->get_state ());
1158 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1160 if (!cassocs.empty()) {
1161 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1163 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1165 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1166 i->first->id().print (buf, sizeof (buf));
1167 can->add_property (X_("copy"), buf);
1168 i->second->id().print (buf, sizeof (buf));
1169 can->add_property (X_("original"), buf);
1170 ca->add_child_nocopy (*can);
1180 node->add_child_nocopy (_locations->get_state());
1183 Locations loc (*this);
1184 // for a template, just create a new Locations, populate it
1185 // with the default start and end, and get the state for that.
1186 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1187 range->set (max_framepos, 0);
1189 XMLNode& locations_state = loc.get_state();
1191 if (ARDOUR::Profile->get_trx() && _locations) {
1192 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1193 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1194 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1195 locations_state.add_child_nocopy ((*i)->get_state ());
1199 node->add_child_nocopy (locations_state);
1202 child = node->add_child ("Bundles");
1204 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1205 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1206 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1208 child->add_child_nocopy (b->get_state());
1213 child = node->add_child ("Routes");
1215 boost::shared_ptr<RouteList> r = routes.reader ();
1217 RoutePublicOrderSorter cmp;
1218 RouteList public_order (*r);
1219 public_order.sort (cmp);
1221 /* the sort should have put control outs first */
1224 assert (_monitor_out == public_order.front());
1227 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1228 if (!(*i)->is_auditioner()) {
1230 child->add_child_nocopy ((*i)->get_state());
1232 child->add_child_nocopy ((*i)->get_template());
1238 playlists->add_state (node, full_state);
1240 child = node->add_child ("RouteGroups");
1241 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1242 child->add_child_nocopy ((*i)->get_state());
1246 XMLNode* gain_child = node->add_child ("Click");
1247 gain_child->add_child_nocopy (_click_io->state (full_state));
1248 gain_child->add_child_nocopy (_click_gain->state (full_state));
1252 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1253 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1257 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1258 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1261 node->add_child_nocopy (_speakers->get_state());
1262 node->add_child_nocopy (_tempo_map->get_state());
1263 node->add_child_nocopy (get_control_protocol_state());
1266 node->add_child_copy (*_extra_xml);
1270 Glib::Threads::Mutex::Lock lm (lua_lock);
1273 luabridge::LuaRef savedstate ((*_lua_save)());
1274 saved = savedstate.cast<std::string>();
1276 lua.collect_garbage ();
1279 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1280 std::string b64s (b64);
1283 XMLNode* script_node = new XMLNode (X_("Script"));
1284 script_node->add_property (X_("lua"), LUA_VERSION);
1285 script_node->add_content (b64s);
1286 node->add_child_nocopy (*script_node);
1293 Session::get_control_protocol_state ()
1295 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1296 return cpm.get_state();
1300 Session::set_state (const XMLNode& node, int version)
1305 XMLProperty const * prop;
1308 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1310 if (node.name() != X_("Session")) {
1311 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1315 if ((prop = node.property ("name")) != 0) {
1316 _name = prop->value ();
1319 if ((prop = node.property (X_("sample-rate"))) != 0) {
1321 _base_frame_rate = atoi (prop->value());
1322 _nominal_frame_rate = _base_frame_rate;
1324 assert (AudioEngine::instance()->running ());
1325 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1326 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1327 if (r.get_value_or (0)) {
1333 setup_raid_path(_session_dir->root_path());
1335 if ((prop = node.property (X_("id-counter"))) != 0) {
1337 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1338 ID::init_counter (x);
1340 /* old sessions used a timebased counter, so fake
1341 the startup ID counter based on a standard
1346 ID::init_counter (now);
1349 if ((prop = node.property (X_("name-counter"))) != 0) {
1350 init_name_id_counter (atoi (prop->value()));
1353 if ((prop = node.property (X_("event-counter"))) != 0) {
1354 Evoral::init_event_id_counter (atoi (prop->value()));
1357 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1358 _midi_ports->set_midi_port_states (child->children());
1361 IO::disable_connecting ();
1363 Stateful::save_extra_xml (node);
1365 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1366 load_options (*child);
1367 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1368 load_options (*child);
1370 error << _("Session: XML state has no options section") << endmsg;
1373 if (version >= 3000) {
1374 if ((child = find_named_node (node, "Metadata")) == 0) {
1375 warning << _("Session: XML state has no metadata section") << endmsg;
1376 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1381 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1382 _speakers->set_state (*child, version);
1385 if ((child = find_named_node (node, "Sources")) == 0) {
1386 error << _("Session: XML state has no sources section") << endmsg;
1388 } else if (load_sources (*child)) {
1392 if ((child = find_named_node (node, "TempoMap")) == 0) {
1393 error << _("Session: XML state has no Tempo Map section") << endmsg;
1395 } else if (_tempo_map->set_state (*child, version)) {
1399 if ((child = find_named_node (node, "Locations")) == 0) {
1400 error << _("Session: XML state has no locations section") << endmsg;
1402 } else if (_locations->set_state (*child, version)) {
1406 locations_changed ();
1408 if (_session_range_location) {
1409 AudioFileSource::set_header_position_offset (_session_range_location->start());
1412 if ((child = find_named_node (node, "Regions")) == 0) {
1413 error << _("Session: XML state has no Regions section") << endmsg;
1415 } else if (load_regions (*child)) {
1419 if ((child = find_named_node (node, "Playlists")) == 0) {
1420 error << _("Session: XML state has no playlists section") << endmsg;
1422 } else if (playlists->load (*this, *child)) {
1426 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1428 } else if (playlists->load_unused (*this, *child)) {
1432 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1433 if (load_compounds (*child)) {
1438 if (version >= 3000) {
1439 if ((child = find_named_node (node, "Bundles")) == 0) {
1440 warning << _("Session: XML state has no bundles section") << endmsg;
1443 /* We can't load Bundles yet as they need to be able
1444 to convert from port names to Port objects, which can't happen until
1446 _bundle_xml_node = new XMLNode (*child);
1450 if (version < 3000) {
1451 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1452 error << _("Session: XML state has no diskstreams section") << endmsg;
1454 } else if (load_diskstreams_2X (*child, version)) {
1459 if ((child = find_named_node (node, "Routes")) == 0) {
1460 error << _("Session: XML state has no routes section") << endmsg;
1462 } else if (load_routes (*child, version)) {
1466 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1467 _diskstreams_2X.clear ();
1469 if (version >= 3000) {
1471 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1472 error << _("Session: XML state has no route groups section") << endmsg;
1474 } else if (load_route_groups (*child, version)) {
1478 } else if (version < 3000) {
1480 if ((child = find_named_node (node, "EditGroups")) == 0) {
1481 error << _("Session: XML state has no edit groups section") << endmsg;
1483 } else if (load_route_groups (*child, version)) {
1487 if ((child = find_named_node (node, "MixGroups")) == 0) {
1488 error << _("Session: XML state has no mix groups section") << endmsg;
1490 } else if (load_route_groups (*child, version)) {
1495 if ((child = find_named_node (node, "Click")) == 0) {
1496 warning << _("Session: XML state has no click section") << endmsg;
1497 } else if (_click_io) {
1498 setup_click_state (&node);
1501 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1502 ControlProtocolManager::instance().set_state (*child, version);
1505 if ((child = find_named_node (node, "Script"))) {
1506 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1507 if (!(*n)->is_content ()) { continue; }
1509 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1511 Glib::Threads::Mutex::Lock lm (lua_lock);
1512 (*_lua_load)(std::string ((const char*)buf, size));
1513 } catch (luabridge::LuaException const& e) {
1514 cerr << "LuaException:" << e.what () << endl;
1520 update_route_record_state ();
1522 /* here beginneth the second phase ... */
1523 set_snapshot_name (_current_snapshot_name);
1525 StateReady (); /* EMIT SIGNAL */
1538 Session::load_routes (const XMLNode& node, int version)
1541 XMLNodeConstIterator niter;
1542 RouteList new_routes;
1544 nlist = node.children();
1548 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1550 boost::shared_ptr<Route> route;
1551 if (version < 3000) {
1552 route = XMLRouteFactory_2X (**niter, version);
1554 route = XMLRouteFactory (**niter, version);
1558 error << _("Session: cannot create Route from XML description.") << endmsg;
1562 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1564 new_routes.push_back (route);
1567 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1569 add_routes (new_routes, false, false, false);
1571 BootMessage (_("Finished adding tracks/busses"));
1576 boost::shared_ptr<Route>
1577 Session::XMLRouteFactory (const XMLNode& node, int version)
1579 boost::shared_ptr<Route> ret;
1581 if (node.name() != "Route") {
1585 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1587 DataType type = DataType::AUDIO;
1588 XMLProperty const * prop = node.property("default-type");
1591 type = DataType (prop->value());
1594 assert (type != DataType::NIL);
1598 boost::shared_ptr<Track> track;
1600 if (type == DataType::AUDIO) {
1601 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1603 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1606 if (track->init()) {
1610 if (track->set_state (node, version)) {
1614 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1615 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1620 enum Route::Flag flags = Route::Flag(0);
1621 XMLProperty const * prop = node.property("flags");
1623 flags = Route::Flag (string_2_enum (prop->value(), flags));
1626 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1628 if (r->init () == 0 && r->set_state (node, version) == 0) {
1629 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1630 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1639 boost::shared_ptr<Route>
1640 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1642 boost::shared_ptr<Route> ret;
1644 if (node.name() != "Route") {
1648 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1650 ds_prop = node.property (X_("diskstream"));
1653 DataType type = DataType::AUDIO;
1654 XMLProperty const * prop = node.property("default-type");
1657 type = DataType (prop->value());
1660 assert (type != DataType::NIL);
1664 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1665 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1669 if (i == _diskstreams_2X.end()) {
1670 error << _("Could not find diskstream for route") << endmsg;
1671 return boost::shared_ptr<Route> ();
1674 boost::shared_ptr<Track> track;
1676 if (type == DataType::AUDIO) {
1677 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1679 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1682 if (track->init()) {
1686 if (track->set_state (node, version)) {
1690 track->set_diskstream (*i);
1692 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1693 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1698 enum Route::Flag flags = Route::Flag(0);
1699 XMLProperty const * prop = node.property("flags");
1701 flags = Route::Flag (string_2_enum (prop->value(), flags));
1704 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1706 if (r->init () == 0 && r->set_state (node, version) == 0) {
1707 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1708 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1718 Session::load_regions (const XMLNode& node)
1721 XMLNodeConstIterator niter;
1722 boost::shared_ptr<Region> region;
1724 nlist = node.children();
1728 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1729 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1730 error << _("Session: cannot create Region from XML description.");
1731 XMLProperty const * name = (**niter).property("name");
1734 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1745 Session::load_compounds (const XMLNode& node)
1747 XMLNodeList calist = node.children();
1748 XMLNodeConstIterator caiter;
1749 XMLProperty const * caprop;
1751 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1752 XMLNode* ca = *caiter;
1756 if ((caprop = ca->property (X_("original"))) == 0) {
1759 orig_id = caprop->value();
1761 if ((caprop = ca->property (X_("copy"))) == 0) {
1764 copy_id = caprop->value();
1766 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1767 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1769 if (!orig || !copy) {
1770 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1776 RegionFactory::add_compound_association (orig, copy);
1783 Session::load_nested_sources (const XMLNode& node)
1786 XMLNodeConstIterator niter;
1788 nlist = node.children();
1790 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1791 if ((*niter)->name() == "Source") {
1793 /* it may already exist, so don't recreate it unnecessarily
1796 XMLProperty const * prop = (*niter)->property (X_("id"));
1798 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1802 ID source_id (prop->value());
1804 if (!source_by_id (source_id)) {
1807 SourceFactory::create (*this, **niter, true);
1809 catch (failed_constructor& err) {
1810 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1817 boost::shared_ptr<Region>
1818 Session::XMLRegionFactory (const XMLNode& node, bool full)
1820 XMLProperty const * type = node.property("type");
1824 const XMLNodeList& nlist = node.children();
1826 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1827 XMLNode *child = (*niter);
1828 if (child->name() == "NestedSource") {
1829 load_nested_sources (*child);
1833 if (!type || type->value() == "audio") {
1834 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1835 } else if (type->value() == "midi") {
1836 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1839 } catch (failed_constructor& err) {
1840 return boost::shared_ptr<Region> ();
1843 return boost::shared_ptr<Region> ();
1846 boost::shared_ptr<AudioRegion>
1847 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1849 XMLProperty const * prop;
1850 boost::shared_ptr<Source> source;
1851 boost::shared_ptr<AudioSource> as;
1853 SourceList master_sources;
1854 uint32_t nchans = 1;
1857 if (node.name() != X_("Region")) {
1858 return boost::shared_ptr<AudioRegion>();
1861 if ((prop = node.property (X_("channels"))) != 0) {
1862 nchans = atoi (prop->value().c_str());
1865 if ((prop = node.property ("name")) == 0) {
1866 cerr << "no name for this region\n";
1870 if ((prop = node.property (X_("source-0"))) == 0) {
1871 if ((prop = node.property ("source")) == 0) {
1872 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1873 return boost::shared_ptr<AudioRegion>();
1877 PBD::ID s_id (prop->value());
1879 if ((source = source_by_id (s_id)) == 0) {
1880 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1881 return boost::shared_ptr<AudioRegion>();
1884 as = boost::dynamic_pointer_cast<AudioSource>(source);
1886 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1887 return boost::shared_ptr<AudioRegion>();
1890 sources.push_back (as);
1892 /* pickup other channels */
1894 for (uint32_t n=1; n < nchans; ++n) {
1895 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1896 if ((prop = node.property (buf)) != 0) {
1898 PBD::ID id2 (prop->value());
1900 if ((source = source_by_id (id2)) == 0) {
1901 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1902 return boost::shared_ptr<AudioRegion>();
1905 as = boost::dynamic_pointer_cast<AudioSource>(source);
1907 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1908 return boost::shared_ptr<AudioRegion>();
1910 sources.push_back (as);
1914 for (uint32_t n = 0; n < nchans; ++n) {
1915 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1916 if ((prop = node.property (buf)) != 0) {
1918 PBD::ID id2 (prop->value());
1920 if ((source = source_by_id (id2)) == 0) {
1921 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1922 return boost::shared_ptr<AudioRegion>();
1925 as = boost::dynamic_pointer_cast<AudioSource>(source);
1927 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1928 return boost::shared_ptr<AudioRegion>();
1930 master_sources.push_back (as);
1935 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1937 /* a final detail: this is the one and only place that we know how long missing files are */
1939 if (region->whole_file()) {
1940 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1941 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1943 sfp->set_length (region->length());
1948 if (!master_sources.empty()) {
1949 if (master_sources.size() != nchans) {
1950 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1952 region->set_master_sources (master_sources);
1960 catch (failed_constructor& err) {
1961 return boost::shared_ptr<AudioRegion>();
1965 boost::shared_ptr<MidiRegion>
1966 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1968 XMLProperty const * prop;
1969 boost::shared_ptr<Source> source;
1970 boost::shared_ptr<MidiSource> ms;
1973 if (node.name() != X_("Region")) {
1974 return boost::shared_ptr<MidiRegion>();
1977 if ((prop = node.property ("name")) == 0) {
1978 cerr << "no name for this region\n";
1982 if ((prop = node.property (X_("source-0"))) == 0) {
1983 if ((prop = node.property ("source")) == 0) {
1984 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1985 return boost::shared_ptr<MidiRegion>();
1989 PBD::ID s_id (prop->value());
1991 if ((source = source_by_id (s_id)) == 0) {
1992 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1993 return boost::shared_ptr<MidiRegion>();
1996 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1998 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1999 return boost::shared_ptr<MidiRegion>();
2002 sources.push_back (ms);
2005 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2006 /* a final detail: this is the one and only place that we know how long missing files are */
2008 if (region->whole_file()) {
2009 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2010 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2012 sfp->set_length (region->length());
2020 catch (failed_constructor& err) {
2021 return boost::shared_ptr<MidiRegion>();
2026 Session::get_sources_as_xml ()
2029 XMLNode* node = new XMLNode (X_("Sources"));
2030 Glib::Threads::Mutex::Lock lm (source_lock);
2032 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2033 node->add_child_nocopy (i->second->get_state());
2040 Session::reset_write_sources (bool mark_write_complete, bool force)
2042 boost::shared_ptr<RouteList> rl = routes.reader();
2043 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2044 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2046 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2047 tr->reset_write_sources(mark_write_complete, force);
2048 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2054 Session::load_sources (const XMLNode& node)
2057 XMLNodeConstIterator niter;
2058 boost::shared_ptr<Source> source; /* don't need this but it stops some
2059 * versions of gcc complaining about
2060 * discarded return values.
2063 nlist = node.children();
2067 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2070 if ((source = XMLSourceFactory (**niter)) == 0) {
2071 error << _("Session: cannot create Source from XML description.") << endmsg;
2074 } catch (MissingSource& err) {
2078 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2079 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2080 PROGRAM_NAME) << endmsg;
2084 if (!no_questions_about_missing_files) {
2085 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2090 switch (user_choice) {
2092 /* user added a new search location, so try again */
2097 /* user asked to quit the entire session load
2102 no_questions_about_missing_files = true;
2106 no_questions_about_missing_files = true;
2113 case DataType::AUDIO:
2114 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2117 case DataType::MIDI:
2118 /* The MIDI file is actually missing so
2119 * just create a new one in the same
2120 * location. Do not announce its
2124 if (!Glib::path_is_absolute (err.path)) {
2125 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2127 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2132 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2133 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2134 /* reset ID to match the missing one */
2135 source->set_id (**niter);
2136 /* Now we can announce it */
2137 SourceFactory::SourceCreated (source);
2148 boost::shared_ptr<Source>
2149 Session::XMLSourceFactory (const XMLNode& node)
2151 if (node.name() != "Source") {
2152 return boost::shared_ptr<Source>();
2156 /* note: do peak building in another thread when loading session state */
2157 return SourceFactory::create (*this, node, true);
2160 catch (failed_constructor& err) {
2161 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2162 return boost::shared_ptr<Source>();
2167 Session::save_template (string template_name, bool replace_existing)
2169 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2173 bool absolute_path = Glib::path_is_absolute (template_name);
2175 /* directory to put the template in */
2176 std::string template_dir_path;
2178 if (!absolute_path) {
2179 std::string user_template_dir(user_template_directory());
2181 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2182 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2183 user_template_dir, g_strerror (errno)) << endmsg;
2187 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2189 template_dir_path = template_name;
2192 if (!ARDOUR::Profile->get_trx()) {
2193 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2194 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2195 template_dir_path) << endmsg;
2199 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2200 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2201 template_dir_path, g_strerror (errno)) << endmsg;
2207 std::string template_file_path;
2209 if (ARDOUR::Profile->get_trx()) {
2210 template_file_path = template_name;
2212 if (absolute_path) {
2213 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2215 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2219 SessionSaveUnderway (); /* EMIT SIGNAL */
2224 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2225 tree.set_root (&get_template());
2228 if (!tree.write (template_file_path)) {
2229 error << _("template not saved") << endmsg;
2233 store_recent_templates (template_file_path);
2239 Session::refresh_disk_space ()
2241 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2243 Glib::Threads::Mutex::Lock lm (space_lock);
2245 /* get freespace on every FS that is part of the session path */
2247 _total_free_4k_blocks = 0;
2248 _total_free_4k_blocks_uncertain = false;
2250 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2252 struct statfs statfsbuf;
2253 statfs (i->path.c_str(), &statfsbuf);
2255 double const scale = statfsbuf.f_bsize / 4096.0;
2257 /* See if this filesystem is read-only */
2258 struct statvfs statvfsbuf;
2259 statvfs (i->path.c_str(), &statvfsbuf);
2261 /* f_bavail can be 0 if it is undefined for whatever
2262 filesystem we are looking at; Samba shares mounted
2263 via GVFS are an example of this.
2265 if (statfsbuf.f_bavail == 0) {
2266 /* block count unknown */
2268 i->blocks_unknown = true;
2269 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2270 /* read-only filesystem */
2272 i->blocks_unknown = false;
2274 /* read/write filesystem with known space */
2275 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2276 i->blocks_unknown = false;
2279 _total_free_4k_blocks += i->blocks;
2280 if (i->blocks_unknown) {
2281 _total_free_4k_blocks_uncertain = true;
2284 #elif defined PLATFORM_WINDOWS
2285 vector<string> scanned_volumes;
2286 vector<string>::iterator j;
2287 vector<space_and_path>::iterator i;
2288 DWORD nSectorsPerCluster, nBytesPerSector,
2289 nFreeClusters, nTotalClusters;
2293 _total_free_4k_blocks = 0;
2295 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2296 strncpy (disk_drive, (*i).path.c_str(), 3);
2300 volume_found = false;
2301 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2303 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2304 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2305 i->blocks = (uint32_t)(nFreeBytes / 4096);
2307 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2308 if (0 == j->compare(disk_drive)) {
2309 volume_found = true;
2314 if (!volume_found) {
2315 scanned_volumes.push_back(disk_drive);
2316 _total_free_4k_blocks += i->blocks;
2321 if (0 == _total_free_4k_blocks) {
2322 strncpy (disk_drive, path().c_str(), 3);
2325 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2327 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2328 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2329 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2336 Session::get_best_session_directory_for_new_audio ()
2338 vector<space_and_path>::iterator i;
2339 string result = _session_dir->root_path();
2341 /* handle common case without system calls */
2343 if (session_dirs.size() == 1) {
2347 /* OK, here's the algorithm we're following here:
2349 We want to select which directory to use for
2350 the next file source to be created. Ideally,
2351 we'd like to use a round-robin process so as to
2352 get maximum performance benefits from splitting
2353 the files across multiple disks.
2355 However, in situations without much diskspace, an
2356 RR approach may end up filling up a filesystem
2357 with new files while others still have space.
2358 Its therefore important to pay some attention to
2359 the freespace in the filesystem holding each
2360 directory as well. However, if we did that by
2361 itself, we'd keep creating new files in the file
2362 system with the most space until it was as full
2363 as all others, thus negating any performance
2364 benefits of this RAID-1 like approach.
2366 So, we use a user-configurable space threshold. If
2367 there are at least 2 filesystems with more than this
2368 much space available, we use RR selection between them.
2369 If not, then we pick the filesystem with the most space.
2371 This gets a good balance between the two
2375 refresh_disk_space ();
2377 int free_enough = 0;
2379 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2380 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2385 if (free_enough >= 2) {
2386 /* use RR selection process, ensuring that the one
2390 i = last_rr_session_dir;
2393 if (++i == session_dirs.end()) {
2394 i = session_dirs.begin();
2397 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2398 SessionDirectory sdir(i->path);
2399 if (sdir.create ()) {
2401 last_rr_session_dir = i;
2406 } while (i != last_rr_session_dir);
2410 /* pick FS with the most freespace (and that
2411 seems to actually work ...)
2414 vector<space_and_path> sorted;
2415 space_and_path_ascending_cmp cmp;
2417 sorted = session_dirs;
2418 sort (sorted.begin(), sorted.end(), cmp);
2420 for (i = sorted.begin(); i != sorted.end(); ++i) {
2421 SessionDirectory sdir(i->path);
2422 if (sdir.create ()) {
2424 last_rr_session_dir = i;
2434 Session::automation_dir () const
2436 return Glib::build_filename (_path, automation_dir_name);
2440 Session::analysis_dir () const
2442 return Glib::build_filename (_path, analysis_dir_name);
2446 Session::plugins_dir () const
2448 return Glib::build_filename (_path, plugins_dir_name);
2452 Session::externals_dir () const
2454 return Glib::build_filename (_path, externals_dir_name);
2458 Session::load_bundles (XMLNode const & node)
2460 XMLNodeList nlist = node.children();
2461 XMLNodeConstIterator niter;
2465 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2466 if ((*niter)->name() == "InputBundle") {
2467 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2468 } else if ((*niter)->name() == "OutputBundle") {
2469 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2471 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2480 Session::load_route_groups (const XMLNode& node, int version)
2482 XMLNodeList nlist = node.children();
2483 XMLNodeConstIterator niter;
2487 if (version >= 3000) {
2489 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2490 if ((*niter)->name() == "RouteGroup") {
2491 RouteGroup* rg = new RouteGroup (*this, "");
2492 add_route_group (rg);
2493 rg->set_state (**niter, version);
2497 } else if (version < 3000) {
2499 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2500 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2501 RouteGroup* rg = new RouteGroup (*this, "");
2502 add_route_group (rg);
2503 rg->set_state (**niter, version);
2512 state_file_filter (const string &str, void* /*arg*/)
2514 return (str.length() > strlen(statefile_suffix) &&
2515 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2519 remove_end(string state)
2521 string statename(state);
2523 string::size_type start,end;
2524 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2525 statename = statename.substr (start+1);
2528 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2529 end = statename.length();
2532 return string(statename.substr (0, end));
2536 Session::possible_states (string path)
2538 vector<string> states;
2539 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2541 transform(states.begin(), states.end(), states.begin(), remove_end);
2543 sort (states.begin(), states.end());
2549 Session::possible_states () const
2551 return possible_states(_path);
2555 Session::add_route_group (RouteGroup* g)
2557 _route_groups.push_back (g);
2558 route_group_added (g); /* EMIT SIGNAL */
2560 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2561 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2562 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2568 Session::remove_route_group (RouteGroup& rg)
2570 list<RouteGroup*>::iterator i;
2572 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2573 _route_groups.erase (i);
2576 route_group_removed (); /* EMIT SIGNAL */
2580 /** Set a new order for our route groups, without adding or removing any.
2581 * @param groups Route group list in the new order.
2584 Session::reorder_route_groups (list<RouteGroup*> groups)
2586 _route_groups = groups;
2588 route_groups_reordered (); /* EMIT SIGNAL */
2594 Session::route_group_by_name (string name)
2596 list<RouteGroup *>::iterator i;
2598 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2599 if ((*i)->name() == name) {
2607 Session::all_route_group() const
2609 return *_all_route_group;
2613 Session::add_commands (vector<Command*> const & cmds)
2615 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2621 Session::add_command (Command* const cmd)
2623 assert (_current_trans);
2624 DEBUG_UNDO_HISTORY (
2625 string_compose ("Current Undo Transaction %1, adding command: %2",
2626 _current_trans->name (),
2628 _current_trans->add_command (cmd);
2631 PBD::StatefulDiffCommand*
2632 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2634 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2640 Session::begin_reversible_command (const string& name)
2642 begin_reversible_command (g_quark_from_string (name.c_str ()));
2645 /** Begin a reversible command using a GQuark to identify it.
2646 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2647 * but there must be as many begin...()s as there are commit...()s.
2650 Session::begin_reversible_command (GQuark q)
2652 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2653 to hold all the commands that are committed. This keeps the order of
2654 commands correct in the history.
2657 if (_current_trans == 0) {
2658 DEBUG_UNDO_HISTORY (string_compose (
2659 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2661 /* start a new transaction */
2662 assert (_current_trans_quarks.empty ());
2663 _current_trans = new UndoTransaction();
2664 _current_trans->set_name (g_quark_to_string (q));
2666 DEBUG_UNDO_HISTORY (
2667 string_compose ("Begin Reversible Command, current transaction: %1",
2668 _current_trans->name ()));
2671 _current_trans_quarks.push_front (q);
2675 Session::abort_reversible_command ()
2677 if (_current_trans != 0) {
2678 DEBUG_UNDO_HISTORY (
2679 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2680 _current_trans->clear();
2681 delete _current_trans;
2683 _current_trans_quarks.clear();
2688 Session::commit_reversible_command (Command *cmd)
2690 assert (_current_trans);
2691 assert (!_current_trans_quarks.empty ());
2696 DEBUG_UNDO_HISTORY (
2697 string_compose ("Current Undo Transaction %1, adding command: %2",
2698 _current_trans->name (),
2700 _current_trans->add_command (cmd);
2703 DEBUG_UNDO_HISTORY (
2704 string_compose ("Commit Reversible Command, current transaction: %1",
2705 _current_trans->name ()));
2707 _current_trans_quarks.pop_front ();
2709 if (!_current_trans_quarks.empty ()) {
2710 DEBUG_UNDO_HISTORY (
2711 string_compose ("Commit Reversible Command, transaction is not "
2712 "top-level, current transaction: %1",
2713 _current_trans->name ()));
2714 /* the transaction we're committing is not the top-level one */
2718 if (_current_trans->empty()) {
2719 /* no commands were added to the transaction, so just get rid of it */
2720 DEBUG_UNDO_HISTORY (
2721 string_compose ("Commit Reversible Command, No commands were "
2722 "added to current transaction: %1",
2723 _current_trans->name ()));
2724 delete _current_trans;
2729 gettimeofday (&now, 0);
2730 _current_trans->set_timestamp (now);
2732 _history.add (_current_trans);
2737 accept_all_audio_files (const string& path, void* /*arg*/)
2739 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2743 if (!AudioFileSource::safe_audio_file_extension (path)) {
2751 accept_all_midi_files (const string& path, void* /*arg*/)
2753 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2757 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2758 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2759 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2763 accept_all_state_files (const string& path, void* /*arg*/)
2765 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2769 std::string const statefile_ext (statefile_suffix);
2770 if (path.length() >= statefile_ext.length()) {
2771 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2778 Session::find_all_sources (string path, set<string>& result)
2783 if (!tree.read (path)) {
2787 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2792 XMLNodeConstIterator niter;
2794 nlist = node->children();
2798 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2800 XMLProperty const * prop;
2802 if ((prop = (*niter)->property (X_("type"))) == 0) {
2806 DataType type (prop->value());
2808 if ((prop = (*niter)->property (X_("name"))) == 0) {
2812 if (Glib::path_is_absolute (prop->value())) {
2813 /* external file, ignore */
2821 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2822 result.insert (found_path);
2830 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2832 vector<string> state_files;
2834 string this_snapshot_path;
2840 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2841 ripped = ripped.substr (0, ripped.length() - 1);
2844 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2846 if (state_files.empty()) {
2851 this_snapshot_path = _path;
2852 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2853 this_snapshot_path += statefile_suffix;
2855 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2857 if (exclude_this_snapshot && *i == this_snapshot_path) {
2861 if (find_all_sources (*i, result) < 0) {
2869 struct RegionCounter {
2870 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2871 AudioSourceList::iterator iter;
2872 boost::shared_ptr<Region> region;
2875 RegionCounter() : count (0) {}
2879 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2881 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2882 return r.get_value_or (1);
2886 Session::cleanup_regions ()
2888 bool removed = false;
2889 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2891 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2893 uint32_t used = playlists->region_use_count (i->second);
2895 if (used == 0 && !i->second->automatic ()) {
2896 boost::weak_ptr<Region> w = i->second;
2899 RegionFactory::map_remove (w);
2906 // re-check to remove parent references of compound regions
2907 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2908 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2912 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2913 if (0 == playlists->region_use_count (i->second)) {
2914 boost::weak_ptr<Region> w = i->second;
2916 RegionFactory::map_remove (w);
2923 /* dump the history list */
2930 Session::can_cleanup_peakfiles () const
2932 if (deletion_in_progress()) {
2935 if (!_writable || (_state_of_the_state & CannotSave)) {
2936 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2939 if (record_status() == Recording) {
2940 error << _("Cannot cleanup peak-files while recording") << endmsg;
2947 Session::cleanup_peakfiles ()
2949 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2954 assert (can_cleanup_peakfiles ());
2955 assert (!peaks_cleanup_in_progres());
2957 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2959 int timeout = 5000; // 5 seconds
2960 while (!SourceFactory::files_with_peaks.empty()) {
2961 Glib::usleep (1000);
2962 if (--timeout < 0) {
2963 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2964 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2969 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2970 boost::shared_ptr<AudioSource> as;
2971 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2972 as->close_peakfile();
2976 PBD::clear_directory (session_directory().peak_path());
2978 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2980 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2981 boost::shared_ptr<AudioSource> as;
2982 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2983 SourceFactory::setup_peakfile(as, true);
2990 Session::cleanup_sources (CleanupReport& rep)
2992 // FIXME: needs adaptation to midi
2994 vector<boost::shared_ptr<Source> > dead_sources;
2997 vector<string> candidates;
2998 vector<string> unused;
2999 set<string> all_sources;
3008 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3010 /* this is mostly for windows which doesn't allow file
3011 * renaming if the file is in use. But we don't special
3012 * case it because we need to know if this causes
3013 * problems, and the easiest way to notice that is to
3014 * keep it in place for all platforms.
3017 request_stop (false);
3019 _butler->wait_until_finished ();
3021 /* consider deleting all unused playlists */
3023 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3028 /* sync the "all regions" property of each playlist with its current state
3031 playlists->sync_all_regions_with_regions ();
3033 /* find all un-used sources */
3038 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3040 SourceMap::iterator tmp;
3045 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3049 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3050 dead_sources.push_back (i->second);
3051 i->second->drop_references ();
3057 /* build a list of all the possible audio directories for the session */
3059 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3060 SessionDirectory sdir ((*i).path);
3061 asp += sdir.sound_path();
3063 audio_path += asp.to_string();
3066 /* build a list of all the possible midi directories for the session */
3068 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3069 SessionDirectory sdir ((*i).path);
3070 msp += sdir.midi_path();
3072 midi_path += msp.to_string();
3074 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3075 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3077 /* find all sources, but don't use this snapshot because the
3078 state file on disk still references sources we may have already
3082 find_all_sources_across_snapshots (all_sources, true);
3084 /* add our current source list
3087 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3088 boost::shared_ptr<FileSource> fs;
3089 SourceMap::iterator tmp = i;
3092 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3094 /* this is mostly for windows which doesn't allow file
3095 * renaming if the file is in use. But we don't special
3096 * case it because we need to know if this causes
3097 * problems, and the easiest way to notice that is to
3098 * keep it in place for all platforms.
3103 if (!fs->is_stub()) {
3105 if (playlists->source_use_count (fs) != 0) {
3106 all_sources.insert (fs->path());
3109 /* we might not remove this source from disk, because it may be used
3110 by other snapshots, but its not being used in this version
3111 so lets get rid of it now, along with any representative regions
3115 RegionFactory::remove_regions_using_source (i->second);
3117 // also remove source from all_sources
3119 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3120 spath = Glib::path_get_basename (*j);
3121 if (spath == i->second->name()) {
3122 all_sources.erase (j);
3135 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3140 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3142 tmppath1 = canonical_path (spath);
3143 tmppath2 = canonical_path ((*i));
3145 if (tmppath1 == tmppath2) {
3152 unused.push_back (spath);
3156 /* now try to move all unused files into the "dead" directory(ies) */
3158 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3163 /* don't move the file across filesystems, just
3164 stick it in the `dead_dir_name' directory
3165 on whichever filesystem it was already on.
3168 if ((*x).find ("/sounds/") != string::npos) {
3170 /* old school, go up 1 level */
3172 newpath = Glib::path_get_dirname (*x); // "sounds"
3173 newpath = Glib::path_get_dirname (newpath); // "session-name"
3177 /* new school, go up 4 levels */
3179 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3180 newpath = Glib::path_get_dirname (newpath); // "session-name"
3181 newpath = Glib::path_get_dirname (newpath); // "interchange"
3182 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3185 newpath = Glib::build_filename (newpath, dead_dir_name);
3187 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3188 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3192 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3194 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3196 /* the new path already exists, try versioning */
3198 char buf[PATH_MAX+1];
3202 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3205 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3206 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3210 if (version == 999) {
3211 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3215 newpath = newpath_v;
3220 /* it doesn't exist, or we can't read it or something */
3224 g_stat ((*x).c_str(), &statbuf);
3226 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3227 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3228 (*x), newpath, strerror (errno))
3233 /* see if there an easy to find peakfile for this file, and remove it.
3236 string base = Glib::path_get_basename (*x);
3237 base += "%A"; /* this is what we add for the channel suffix of all native files,
3238 or for the first channel of embedded files. it will miss
3239 some peakfiles for other channels
3241 string peakpath = construct_peak_filepath (base);
3243 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3244 if (::g_unlink (peakpath.c_str()) != 0) {
3245 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3246 peakpath, _path, strerror (errno))
3248 /* try to back out */
3249 ::rename (newpath.c_str(), _path.c_str());
3254 rep.paths.push_back (*x);
3255 rep.space += statbuf.st_size;
3258 /* dump the history list */
3262 /* save state so we don't end up a session file
3263 referring to non-existent sources.
3270 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3276 Session::cleanup_trash_sources (CleanupReport& rep)
3278 // FIXME: needs adaptation for MIDI
3280 vector<space_and_path>::iterator i;
3286 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3288 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3290 clear_directory (dead_dir, &rep.space, &rep.paths);
3297 Session::set_dirty ()
3299 /* never mark session dirty during loading */
3301 if (_state_of_the_state & Loading) {
3305 bool was_dirty = dirty();
3307 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3311 DirtyChanged(); /* EMIT SIGNAL */
3317 Session::set_clean ()
3319 bool was_dirty = dirty();
3321 _state_of_the_state = Clean;
3325 DirtyChanged(); /* EMIT SIGNAL */
3330 Session::set_deletion_in_progress ()
3332 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3336 Session::clear_deletion_in_progress ()
3338 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3342 Session::add_controllable (boost::shared_ptr<Controllable> c)
3344 /* this adds a controllable to the list managed by the Session.
3345 this is a subset of those managed by the Controllable class
3346 itself, and represents the only ones whose state will be saved
3347 as part of the session.
3350 Glib::Threads::Mutex::Lock lm (controllables_lock);
3351 controllables.insert (c);
3354 struct null_deleter { void operator()(void const *) const {} };
3357 Session::remove_controllable (Controllable* c)
3359 if (_state_of_the_state & Deletion) {
3363 Glib::Threads::Mutex::Lock lm (controllables_lock);
3365 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3367 if (x != controllables.end()) {
3368 controllables.erase (x);
3372 boost::shared_ptr<Controllable>
3373 Session::controllable_by_id (const PBD::ID& id)
3375 Glib::Threads::Mutex::Lock lm (controllables_lock);
3377 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3378 if ((*i)->id() == id) {
3383 return boost::shared_ptr<Controllable>();
3386 boost::shared_ptr<Controllable>
3387 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3389 boost::shared_ptr<Controllable> c;
3390 boost::shared_ptr<Route> r;
3392 switch (desc.top_level_type()) {
3393 case ControllableDescriptor::NamedRoute:
3395 std::string str = desc.top_level_name();
3396 if (str == "Master" || str == "master") {
3398 } else if (str == "control" || str == "listen") {
3401 r = route_by_name (desc.top_level_name());
3406 case ControllableDescriptor::RemoteControlID:
3407 r = route_by_remote_id (desc.rid());
3410 case ControllableDescriptor::SelectionCount:
3411 r = route_by_selected_count (desc.selection_id());
3419 switch (desc.subtype()) {
3420 case ControllableDescriptor::Gain:
3421 c = r->gain_control ();
3424 case ControllableDescriptor::Trim:
3425 c = r->trim()->gain_control ();
3428 case ControllableDescriptor::Solo:
3429 c = r->solo_control();
3432 case ControllableDescriptor::Mute:
3433 c = r->mute_control();
3436 case ControllableDescriptor::Recenable:
3438 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3441 c = t->rec_enable_control ();
3446 case ControllableDescriptor::PanDirection:
3447 c = r->pan_azimuth_control();
3450 case ControllableDescriptor::PanWidth:
3451 c = r->pan_width_control();
3454 case ControllableDescriptor::PanElevation:
3455 c = r->pan_elevation_control();
3458 case ControllableDescriptor::Balance:
3459 /* XXX simple pan control */
3462 case ControllableDescriptor::PluginParameter:
3464 uint32_t plugin = desc.target (0);
3465 uint32_t parameter_index = desc.target (1);
3467 /* revert to zero based counting */
3473 if (parameter_index > 0) {
3477 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3480 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3481 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3486 case ControllableDescriptor::SendGain: {
3487 uint32_t send = desc.target (0);
3491 c = r->send_level_controllable (send);
3496 /* relax and return a null pointer */
3504 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3507 Stateful::add_instant_xml (node, _path);
3510 if (write_to_config) {
3511 Config->add_instant_xml (node);
3516 Session::instant_xml (const string& node_name)
3518 return Stateful::instant_xml (node_name, _path);
3522 Session::save_history (string snapshot_name)
3530 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3531 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3535 if (snapshot_name.empty()) {
3536 snapshot_name = _current_snapshot_name;
3539 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3540 const string backup_filename = history_filename + backup_suffix;
3541 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3542 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3544 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3545 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3546 error << _("could not backup old history file, current history not saved") << endmsg;
3551 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3553 if (!tree.write (xml_path))
3555 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3557 if (g_remove (xml_path.c_str()) != 0) {
3558 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3559 xml_path, g_strerror (errno)) << endmsg;
3561 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3562 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3563 backup_path, g_strerror (errno)) << endmsg;
3573 Session::restore_history (string snapshot_name)
3577 if (snapshot_name.empty()) {
3578 snapshot_name = _current_snapshot_name;
3581 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3582 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3584 info << "Loading history from " << xml_path << endmsg;
3586 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3587 info << string_compose (_("%1: no history file \"%2\" for this session."),
3588 _name, xml_path) << endmsg;
3592 if (!tree.read (xml_path)) {
3593 error << string_compose (_("Could not understand session history file \"%1\""),
3594 xml_path) << endmsg;
3601 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3604 UndoTransaction* ut = new UndoTransaction ();
3607 ut->set_name(t->property("name")->value());
3608 stringstream ss(t->property("tv-sec")->value());
3610 ss.str(t->property("tv-usec")->value());
3612 ut->set_timestamp(tv);
3614 for (XMLNodeConstIterator child_it = t->children().begin();
3615 child_it != t->children().end(); child_it++)
3617 XMLNode *n = *child_it;
3620 if (n->name() == "MementoCommand" ||
3621 n->name() == "MementoUndoCommand" ||
3622 n->name() == "MementoRedoCommand") {
3624 if ((c = memento_command_factory(n))) {
3628 } else if (n->name() == "NoteDiffCommand") {
3629 PBD::ID id (n->property("midi-source")->value());
3630 boost::shared_ptr<MidiSource> midi_source =
3631 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3633 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3635 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3638 } else if (n->name() == "SysExDiffCommand") {
3640 PBD::ID id (n->property("midi-source")->value());
3641 boost::shared_ptr<MidiSource> midi_source =
3642 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3644 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3646 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3649 } else if (n->name() == "PatchChangeDiffCommand") {
3651 PBD::ID id (n->property("midi-source")->value());
3652 boost::shared_ptr<MidiSource> midi_source =
3653 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3655 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3657 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3660 } else if (n->name() == "StatefulDiffCommand") {
3661 if ((c = stateful_diff_command_factory (n))) {
3662 ut->add_command (c);
3665 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3676 Session::config_changed (std::string p, bool ours)
3682 if (p == "seamless-loop") {
3684 } else if (p == "rf-speed") {
3686 } else if (p == "auto-loop") {
3688 } else if (p == "auto-input") {
3690 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3691 /* auto-input only makes a difference if we're rolling */
3692 set_track_monitor_input_status (!config.get_auto_input());
3695 } else if (p == "punch-in") {
3699 if ((location = _locations->auto_punch_location()) != 0) {
3701 if (config.get_punch_in ()) {
3702 replace_event (SessionEvent::PunchIn, location->start());
3704 remove_event (location->start(), SessionEvent::PunchIn);
3708 } else if (p == "punch-out") {
3712 if ((location = _locations->auto_punch_location()) != 0) {
3714 if (config.get_punch_out()) {
3715 replace_event (SessionEvent::PunchOut, location->end());
3717 clear_events (SessionEvent::PunchOut);
3721 } else if (p == "edit-mode") {
3723 Glib::Threads::Mutex::Lock lm (playlists->lock);
3725 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3726 (*i)->set_edit_mode (Config->get_edit_mode ());
3729 } else if (p == "use-video-sync") {
3731 waiting_for_sync_offset = config.get_use_video_sync();
3733 } else if (p == "mmc-control") {
3735 //poke_midi_thread ();
3737 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3739 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3741 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3743 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3745 } else if (p == "midi-control") {
3747 //poke_midi_thread ();
3749 } else if (p == "raid-path") {
3751 setup_raid_path (config.get_raid_path());
3753 } else if (p == "timecode-format") {
3757 } else if (p == "video-pullup") {
3761 } else if (p == "seamless-loop") {
3763 if (play_loop && transport_rolling()) {
3764 // to reset diskstreams etc
3765 request_play_loop (true);
3768 } else if (p == "rf-speed") {
3770 cumulative_rf_motion = 0;
3773 } else if (p == "click-sound") {
3775 setup_click_sounds (1);
3777 } else if (p == "click-emphasis-sound") {
3779 setup_click_sounds (-1);
3781 } else if (p == "clicking") {
3783 if (Config->get_clicking()) {
3784 if (_click_io && click_data) { // don't require emphasis data
3791 } else if (p == "click-gain") {
3794 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3797 } else if (p == "send-mtc") {
3799 if (Config->get_send_mtc ()) {
3800 /* mark us ready to send */
3801 next_quarter_frame_to_send = 0;
3804 } else if (p == "send-mmc") {
3806 _mmc->enable_send (Config->get_send_mmc ());
3808 } else if (p == "midi-feedback") {
3810 session_midi_feedback = Config->get_midi_feedback();
3812 } else if (p == "jack-time-master") {
3814 engine().reset_timebase ();
3816 } else if (p == "native-file-header-format") {
3818 if (!first_file_header_format_reset) {
3819 reset_native_file_format ();
3822 first_file_header_format_reset = false;
3824 } else if (p == "native-file-data-format") {
3826 if (!first_file_data_format_reset) {
3827 reset_native_file_format ();
3830 first_file_data_format_reset = false;
3832 } else if (p == "external-sync") {
3833 if (!config.get_external_sync()) {
3834 drop_sync_source ();
3836 switch_to_sync_source (Config->get_sync_source());
3838 } else if (p == "denormal-model") {
3840 } else if (p == "history-depth") {
3841 set_history_depth (Config->get_history_depth());
3842 } else if (p == "remote-model") {
3843 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3846 } else if (p == "initial-program-change") {
3848 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3851 buf[0] = MIDI::program; // channel zero by default
3852 buf[1] = (Config->get_initial_program_change() & 0x7f);
3854 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3856 } else if (p == "solo-mute-override") {
3857 // catch_up_on_solo_mute_override ();
3858 } else if (p == "listen-position" || p == "pfl-position") {
3859 listen_position_changed ();
3860 } else if (p == "solo-control-is-listen-control") {
3861 solo_control_mode_changed ();
3862 } else if (p == "solo-mute-gain") {
3863 _solo_cut_control->Changed();
3864 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3865 last_timecode_valid = false;
3866 } else if (p == "playback-buffer-seconds") {
3867 AudioSource::allocate_working_buffers (frame_rate());
3868 } else if (p == "ltc-source-port") {
3869 reconnect_ltc_input ();
3870 } else if (p == "ltc-sink-port") {
3871 reconnect_ltc_output ();
3872 } else if (p == "timecode-generator-offset") {
3873 ltc_tx_parse_offset();
3874 } else if (p == "auto-return-target-list") {
3875 follow_playhead_priority ();
3882 Session::set_history_depth (uint32_t d)
3884 _history.set_depth (d);
3888 Session::load_diskstreams_2X (XMLNode const & node, int)
3891 XMLNodeConstIterator citer;
3893 clist = node.children();
3895 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3898 /* diskstreams added automatically by DiskstreamCreated handler */
3899 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3900 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3901 _diskstreams_2X.push_back (dsp);
3903 error << _("Session: unknown diskstream type in XML") << endmsg;
3907 catch (failed_constructor& err) {
3908 error << _("Session: could not load diskstream via XML state") << endmsg;
3916 /** Connect things to the MMC object */
3918 Session::setup_midi_machine_control ()
3920 _mmc = new MIDI::MachineControl;
3922 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
3923 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
3925 if (!async_out || !async_out) {
3929 /* XXXX argh, passing raw pointers back into libmidi++ */
3931 MIDI::Port* mmc_in = async_in.get();
3932 MIDI::Port* mmc_out = async_out.get();
3934 _mmc->set_ports (mmc_in, mmc_out);
3936 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3937 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3938 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3939 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3940 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3941 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3942 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3943 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3944 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3945 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3946 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3947 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3948 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3950 /* also handle MIDI SPP because its so common */
3952 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3953 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3954 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3957 boost::shared_ptr<Controllable>
3958 Session::solo_cut_control() const
3960 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3961 controls in Ardour that currently get presented to the user in the GUI that require
3962 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3964 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3965 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3969 return _solo_cut_control;
3973 Session::save_snapshot_name (const std::string & n)
3975 /* assure Stateful::_instant_xml is loaded
3976 * add_instant_xml() only adds to existing data and defaults
3977 * to use an empty Tree otherwise
3979 instant_xml ("LastUsedSnapshot");
3981 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
3982 last_used_snapshot->add_property ("name", string(n));
3983 add_instant_xml (*last_used_snapshot, false);
3987 Session::set_snapshot_name (const std::string & n)
3989 _current_snapshot_name = n;
3990 save_snapshot_name (n);
3994 Session::rename (const std::string& new_name)
3996 string legal_name = legalize_for_path (new_name);
4002 string const old_sources_root = _session_dir->sources_root();
4004 if (!_writable || (_state_of_the_state & CannotSave)) {
4005 error << _("Cannot rename read-only session.") << endmsg;
4006 return 0; // don't show "messed up" warning
4008 if (record_status() == Recording) {
4009 error << _("Cannot rename session while recording") << endmsg;
4010 return 0; // don't show "messed up" warning
4013 StateProtector stp (this);
4018 * interchange subdirectory
4022 * Backup files are left unchanged and not renamed.
4025 /* Windows requires that we close all files before attempting the
4026 * rename. This works on other platforms, but isn't necessary there.
4027 * Leave it in place for all platforms though, since it may help
4028 * catch issues that could arise if the way Source files work ever
4029 * change (since most developers are not using Windows).
4032 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4033 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4039 /* pass one: not 100% safe check that the new directory names don't
4043 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4047 /* this is a stupid hack because Glib::path_get_dirname() is
4048 * lexical-only, and so passing it /a/b/c/ gives a different
4049 * result than passing it /a/b/c ...
4052 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4053 oldstr = oldstr.substr (0, oldstr.length() - 1);
4056 string base = Glib::path_get_dirname (oldstr);
4058 newstr = Glib::build_filename (base, legal_name);
4060 cerr << "Looking for " << newstr << endl;
4062 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4063 cerr << " exists\n";
4072 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4078 /* this is a stupid hack because Glib::path_get_dirname() is
4079 * lexical-only, and so passing it /a/b/c/ gives a different
4080 * result than passing it /a/b/c ...
4083 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4084 oldstr = oldstr.substr (0, oldstr.length() - 1);
4087 string base = Glib::path_get_dirname (oldstr);
4088 newstr = Glib::build_filename (base, legal_name);
4090 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4092 cerr << "Rename " << oldstr << " => " << newstr << endl;
4093 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4094 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4095 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4099 /* Reset path in "session dirs" */
4104 /* reset primary SessionDirectory object */
4107 (*_session_dir) = newstr;
4112 /* now rename directory below session_dir/interchange */
4114 string old_interchange_dir;
4115 string new_interchange_dir;
4117 /* use newstr here because we renamed the path
4118 * (folder/directory) that used to be oldstr to newstr above
4121 v.push_back (newstr);
4122 v.push_back (interchange_dir_name);
4123 v.push_back (Glib::path_get_basename (oldstr));
4125 old_interchange_dir = Glib::build_filename (v);
4128 v.push_back (newstr);
4129 v.push_back (interchange_dir_name);
4130 v.push_back (legal_name);
4132 new_interchange_dir = Glib::build_filename (v);
4134 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4136 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4137 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4138 old_interchange_dir, new_interchange_dir,
4141 error << string_compose (_("renaming %s as %2 failed (%3)"),
4142 old_interchange_dir, new_interchange_dir,
4151 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4152 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4154 cerr << "Rename " << oldstr << " => " << newstr << endl;
4156 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4157 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4158 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4164 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4166 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4167 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4169 cerr << "Rename " << oldstr << " => " << newstr << endl;
4171 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4172 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4173 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4178 /* remove old name from recent sessions */
4179 remove_recent_sessions (_path);
4182 /* update file source paths */
4184 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4185 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4187 string p = fs->path ();
4188 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4190 SourceFactory::setup_peakfile(i->second, true);
4194 set_snapshot_name (new_name);
4199 /* save state again to get everything just right */
4201 save_state (_current_snapshot_name);
4203 /* add to recent sessions */
4205 store_recent_sessions (new_name, _path);
4211 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4213 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4217 if (!tree.read (xmlpath)) {
4225 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4228 bool found_sr = false;
4229 bool found_data_format = false;
4231 if (get_session_info_from_path (tree, xmlpath)) {
4237 XMLProperty const * prop;
4238 XMLNode const * root (tree.root());
4240 if ((prop = root->property (X_("sample-rate"))) != 0) {
4241 sample_rate = atoi (prop->value());
4245 const XMLNodeList& children (root->children());
4246 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4247 const XMLNode* child = *c;
4248 if (child->name() == "Config") {
4249 const XMLNodeList& options (child->children());
4250 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4251 XMLNode const * option = *oc;
4252 XMLProperty const * name = option->property("name");
4258 if (name->value() == "native-file-data-format") {
4259 XMLProperty const * value = option->property ("value");
4261 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4263 found_data_format = true;
4269 if (found_data_format) {
4274 return !(found_sr && found_data_format); // zero if they are both found
4278 Session::get_snapshot_from_instant (const std::string& session_dir)
4280 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4282 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4287 if (!tree.read (instant_xml_path)) {
4291 XMLProperty const * prop;
4292 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4293 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4294 return prop->value();
4300 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4301 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4304 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4308 SourcePathMap source_path_map;
4310 boost::shared_ptr<AudioFileSource> afs;
4315 Glib::Threads::Mutex::Lock lm (source_lock);
4317 cerr << " total sources = " << sources.size();
4319 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4320 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4326 if (fs->within_session()) {
4330 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4331 source_path_map[fs->path()].push_back (fs);
4333 SeveralFileSources v;
4335 source_path_map.insert (make_pair (fs->path(), v));
4341 cerr << " fsources = " << total << endl;
4343 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4345 /* tell caller where we are */
4347 string old_path = i->first;
4349 callback (n, total, old_path);
4351 cerr << old_path << endl;
4355 switch (i->second.front()->type()) {
4356 case DataType::AUDIO:
4357 new_path = new_audio_source_path_for_embedded (old_path);
4360 case DataType::MIDI:
4361 /* XXX not implemented yet */
4365 if (new_path.empty()) {
4369 cerr << "Move " << old_path << " => " << new_path << endl;
4371 if (!copy_file (old_path, new_path)) {
4372 cerr << "failed !\n";
4376 /* make sure we stop looking in the external
4377 dir/folder. Remember, this is an all-or-nothing
4378 operations, it doesn't merge just some files.
4380 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4382 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4383 (*f)->set_path (new_path);
4388 save_state ("", false, false);
4394 bool accept_all_files (string const &, void *)
4400 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4402 /* 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.
4407 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4409 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4411 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4413 v.push_back (new_session_folder); /* full path */
4414 v.push_back (interchange_dir_name);
4415 v.push_back (new_session_path); /* just one directory/folder */
4416 v.push_back (typedir);
4417 v.push_back (Glib::path_get_basename (old_path));
4419 return Glib::build_filename (v);
4423 Session::save_as (SaveAs& saveas)
4425 vector<string> files;
4426 string current_folder = Glib::path_get_dirname (_path);
4427 string new_folder = legalize_for_path (saveas.new_name);
4428 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4429 int64_t total_bytes = 0;
4433 int32_t internal_file_cnt = 0;
4435 vector<string> do_not_copy_extensions;
4436 do_not_copy_extensions.push_back (statefile_suffix);
4437 do_not_copy_extensions.push_back (pending_suffix);
4438 do_not_copy_extensions.push_back (backup_suffix);
4439 do_not_copy_extensions.push_back (temp_suffix);
4440 do_not_copy_extensions.push_back (history_suffix);
4442 /* get total size */
4444 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4446 /* need to clear this because
4447 * find_files_matching_filter() is cumulative
4452 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4454 all += files.size();
4456 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4458 g_stat ((*i).c_str(), &gsb);
4459 total_bytes += gsb.st_size;
4463 /* save old values so we can switch back if we are not switching to the new session */
4465 string old_path = _path;
4466 string old_name = _name;
4467 string old_snapshot = _current_snapshot_name;
4468 string old_sd = _session_dir->root_path();
4469 vector<string> old_search_path[DataType::num_types];
4470 string old_config_search_path[DataType::num_types];
4472 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4473 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4474 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4475 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4477 /* switch session directory */
4479 (*_session_dir) = to_dir;
4481 /* create new tree */
4483 if (!_session_dir->create()) {
4484 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4489 /* copy all relevant files. Find each location in session_dirs,
4490 * and copy files from there to target.
4493 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4495 /* need to clear this because
4496 * find_files_matching_filter() is cumulative
4501 const size_t prefix_len = (*sd).path.size();
4503 /* Work just on the files within this session dir */
4505 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4507 /* add dir separator to protect against collisions with
4508 * track names (e.g. track named "audiofiles" or
4512 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4513 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4514 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4516 /* copy all the files. Handling is different for media files
4517 than others because of the *silly* subtree we have below the interchange
4518 folder. That really was a bad idea, but I'm not fixing it as part of
4519 implementing ::save_as().
4522 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4524 std::string from = *i;
4527 string filename = Glib::path_get_basename (from);
4528 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4529 if (filename == ".DS_STORE") {
4534 if (from.find (audiofile_dir_string) != string::npos) {
4536 /* audio file: only copy if asked */
4538 if (saveas.include_media && saveas.copy_media) {
4540 string to = make_new_media_path (*i, to_dir, new_folder);
4542 info << "media file copying from " << from << " to " << to << endmsg;
4544 if (!copy_file (from, to)) {
4545 throw Glib::FileError (Glib::FileError::IO_ERROR,
4546 string_compose(_("\ncopying \"%1\" failed !"), from));
4550 /* we found media files inside the session folder */
4552 internal_file_cnt++;
4554 } else if (from.find (midifile_dir_string) != string::npos) {
4556 /* midi file: always copy unless
4557 * creating an empty new session
4560 if (saveas.include_media) {
4562 string to = make_new_media_path (*i, to_dir, new_folder);
4564 info << "media file copying from " << from << " to " << to << endmsg;
4566 if (!copy_file (from, to)) {
4567 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4571 /* we found media files inside the session folder */
4573 internal_file_cnt++;
4575 } else if (from.find (analysis_dir_string) != string::npos) {
4577 /* make sure analysis dir exists in
4578 * new session folder, but we're not
4579 * copying analysis files here, see
4583 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4588 /* normal non-media file. Don't copy state, history, etc.
4591 bool do_copy = true;
4593 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4594 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4595 /* end of filename matches extension, do not copy file */
4601 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4602 /* don't copy peakfiles if
4603 * we're not copying media
4609 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4611 info << "attempting to make directory/folder " << to << endmsg;
4613 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4614 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4617 info << "attempting to copy " << from << " to " << to << endmsg;
4619 if (!copy_file (from, to)) {
4620 throw Glib::FileError (Glib::FileError::IO_ERROR,
4621 string_compose(_("\ncopying \"%1\" failed !"), from));
4626 /* measure file size even if we're not going to copy so that our Progress
4627 signals are correct, since we included these do-not-copy files
4628 in the computation of the total size and file count.
4632 g_stat (from.c_str(), &gsb);
4633 copied += gsb.st_size;
4636 double fraction = (double) copied / total_bytes;
4638 bool keep_going = true;
4640 if (saveas.copy_media) {
4642 /* no need or expectation of this if
4643 * media is not being copied, because
4644 * it will be fast(ish).
4647 /* tell someone "X percent, file M of N"; M is one-based */
4649 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4657 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4663 /* copy optional folders, if any */
4665 string old = plugins_dir ();
4666 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4667 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4668 copy_files (old, newdir);
4671 old = externals_dir ();
4672 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4673 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4674 copy_files (old, newdir);
4677 old = automation_dir ();
4678 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4679 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4680 copy_files (old, newdir);
4683 if (saveas.include_media) {
4685 if (saveas.copy_media) {
4686 #ifndef PLATFORM_WINDOWS
4687 /* There are problems with analysis files on
4688 * Windows, because they used a colon in their
4689 * names as late as 4.0. Colons are not legal
4690 * under Windows even if NTFS allows them.
4692 * This is a tricky problem to solve so for
4693 * just don't copy these files. They will be
4694 * regenerated as-needed anyway, subject to the
4695 * existing issue that the filenames will be
4696 * rejected by Windows, which is a separate
4697 * problem (though related).
4700 /* only needed if we are copying media, since the
4701 * analysis data refers to media data
4704 old = analysis_dir ();
4705 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4706 string newdir = Glib::build_filename (to_dir, "analysis");
4707 copy_files (old, newdir);
4709 #endif /* PLATFORM_WINDOWS */
4715 set_snapshot_name (saveas.new_name);
4716 _name = saveas.new_name;
4718 if (saveas.include_media && !saveas.copy_media) {
4720 /* reset search paths of the new session (which we're pretending to be right now) to
4721 include the original session search path, so we can still find all audio.
4724 if (internal_file_cnt) {
4725 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4726 ensure_search_path_includes (*s, DataType::AUDIO);
4727 cerr << "be sure to include " << *s << " for audio" << endl;
4730 /* we do not do this for MIDI because we copy
4731 all MIDI files if saveas.include_media is
4737 bool was_dirty = dirty ();
4739 save_state ("", false, false, !saveas.include_media);
4740 save_default_options ();
4742 if (saveas.copy_media && saveas.copy_external) {
4743 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4744 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4748 saveas.final_session_folder_name = _path;
4750 store_recent_sessions (_name, _path);
4752 if (!saveas.switch_to) {
4754 /* switch back to the way things were */
4758 set_snapshot_name (old_snapshot);
4760 (*_session_dir) = old_sd;
4766 if (internal_file_cnt) {
4767 /* reset these to their original values */
4768 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4769 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4774 /* prune session dirs, and update disk space statistics
4779 session_dirs.clear ();
4780 session_dirs.push_back (sp);
4781 refresh_disk_space ();
4783 /* ensure that all existing tracks reset their current capture source paths
4785 reset_write_sources (true, true);
4787 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4788 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4791 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4792 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4798 if (fs->within_session()) {
4799 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4800 fs->set_path (newpath);
4805 } catch (Glib::FileError& e) {
4807 saveas.failure_message = e.what();
4809 /* recursively remove all the directories */
4811 remove_directory (to_dir);
4819 saveas.failure_message = _("unknown reason");
4821 /* recursively remove all the directories */
4823 remove_directory (to_dir);