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/basename.h"
65 #include "pbd/debug.h"
66 #include "pbd/enumwriter.h"
67 #include "pbd/error.h"
68 #include "pbd/file_utils.h"
69 #include "pbd/pathexpand.h"
70 #include "pbd/pthread_utils.h"
71 #include "pbd/stacktrace.h"
72 #include "pbd/convert.h"
73 #include "pbd/localtime_r.h"
74 #include "pbd/unwind.h"
76 #include "ardour/amp.h"
77 #include "ardour/async_midi_port.h"
78 #include "ardour/audio_diskstream.h"
79 #include "ardour/audio_track.h"
80 #include "ardour/audioengine.h"
81 #include "ardour/audiofilesource.h"
82 #include "ardour/audioregion.h"
83 #include "ardour/automation_control.h"
84 #include "ardour/boost_debug.h"
85 #include "ardour/butler.h"
86 #include "ardour/controllable_descriptor.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"
122 #include "ardour/vca.h"
123 #include "ardour/vca_manager.h"
125 #include "control_protocol/control_protocol.h"
127 #include "LuaBridge/LuaBridge.h"
133 using namespace ARDOUR;
136 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
139 Session::pre_engine_init (string fullpath)
141 if (fullpath.empty()) {
143 throw failed_constructor();
146 /* discover canonical fullpath */
148 _path = canonical_path(fullpath);
151 if (Profile->get_trx() ) {
152 // Waves TracksLive has a usecase of session replacement with a new one.
153 // We should check session state file (<session_name>.ardour) existance
154 // to determine if the session is new or not
156 string full_session_name = Glib::build_filename( fullpath, _name );
157 full_session_name += statefile_suffix;
159 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
161 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
164 /* finish initialization that can't be done in a normal C++ constructor
168 timerclear (&last_mmc_step);
169 g_atomic_int_set (&processing_prohibited, 0);
170 g_atomic_int_set (&_record_status, Disabled);
171 g_atomic_int_set (&_playback_load, 100);
172 g_atomic_int_set (&_capture_load, 100);
174 _all_route_group->set_active (true, this);
175 interpolation.add_channel_to (0, 0);
176 _vca_manager = new VCAManager (*this);
178 if (config.get_use_video_sync()) {
179 waiting_for_sync_offset = true;
181 waiting_for_sync_offset = false;
184 last_rr_session_dir = session_dirs.begin();
186 set_history_depth (Config->get_history_depth());
188 /* default: assume simple stereo speaker configuration */
190 _speakers->setup_default_speakers (2);
192 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
193 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
194 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
195 add_controllable (_solo_cut_control);
197 /* These are all static "per-class" signals */
199 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
200 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
201 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
202 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
203 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
205 /* stop IO objects from doing stuff until we're ready for them */
207 Delivery::disable_panners ();
208 IO::disable_connecting ();
212 Session::post_engine_init ()
214 BootMessage (_("Set block size and sample rate"));
216 set_block_size (_engine.samples_per_cycle());
217 set_frame_rate (_engine.sample_rate());
219 BootMessage (_("Using configuration"));
221 _midi_ports = new MidiPortManager;
223 MIDISceneChanger* msc;
225 _scene_changer = msc = new MIDISceneChanger (*this);
226 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
227 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
229 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
230 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
232 setup_midi_machine_control ();
234 if (_butler->start_thread()) {
238 if (start_midi_thread ()) {
242 setup_click_sounds (0);
243 setup_midi_control ();
245 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
246 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
249 /* tempo map requires sample rate knowledge */
252 _tempo_map = new TempoMap (_current_frame_rate);
253 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
254 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
256 /* MidiClock requires a tempo map */
259 midi_clock = new MidiClockTicker ();
260 midi_clock->set_session (this);
262 /* crossfades require sample rate knowledge */
264 SndFileSource::setup_standard_crossfades (*this, frame_rate());
265 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
267 AudioDiskstream::allocate_working_buffers();
268 refresh_disk_space ();
270 /* we're finally ready to call set_state() ... all objects have
271 * been created, the engine is running.
275 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
279 // set_state() will call setup_raid_path(), but if it's a new session we need
280 // to call setup_raid_path() here.
281 setup_raid_path (_path);
286 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
287 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
289 Config->map_parameters (ff);
290 config.map_parameters (ft);
291 _butler->map_parameters ();
293 /* Reset all panners */
295 Delivery::reset_panners ();
297 /* this will cause the CPM to instantiate any protocols that are in use
298 * (or mandatory), which will pass it this Session, and then call
299 * set_state() on each instantiated protocol to match stored state.
302 ControlProtocolManager::instance().set_session (this);
304 /* This must be done after the ControlProtocolManager set_session above,
305 as it will set states for ports which the ControlProtocolManager creates.
308 // XXX set state of MIDI::Port's
309 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
311 /* And this must be done after the MIDI::Manager::set_port_states as
312 * it will try to make connections whose details are loaded by set_port_states.
317 /* Let control protocols know that we are now all connected, so they
318 * could start talking to surfaces if they want to.
321 ControlProtocolManager::instance().midi_connectivity_established ();
323 if (_is_new && !no_auto_connect()) {
324 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
325 auto_connect_master_bus ();
328 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
330 /* update latencies */
332 initialize_latencies ();
334 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
335 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
336 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
338 } catch (AudioEngine::PortRegistrationFailure& err) {
339 /* handle this one in a different way than all others, so that its clear what happened */
340 error << err.what() << endmsg;
346 BootMessage (_("Reset Remote Controls"));
348 // send_full_time_code (0);
349 _engine.transport_locate (0);
351 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
352 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
354 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
357 /* initial program change will be delivered later; see ::config_changed() */
359 _state_of_the_state = Clean;
361 Port::set_connecting_blocked (false);
363 DirtyChanged (); /* EMIT SIGNAL */
367 } else if (state_was_pending) {
369 remove_pending_capture_state ();
370 state_was_pending = false;
373 /* Now, finally, we can fill the playback buffers */
375 BootMessage (_("Filling playback buffers"));
377 boost::shared_ptr<RouteList> rl = routes.reader();
378 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
379 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
380 if (trk && !trk->hidden()) {
381 trk->seek (_transport_frame, true);
389 Session::session_loaded ()
393 _state_of_the_state = Clean;
395 DirtyChanged (); /* EMIT SIGNAL */
399 } else if (state_was_pending) {
401 remove_pending_capture_state ();
402 state_was_pending = false;
405 /* Now, finally, we can fill the playback buffers */
407 BootMessage (_("Filling playback buffers"));
408 force_locate (_transport_frame, false);
412 Session::raid_path () const
414 Searchpath raid_search_path;
416 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
417 raid_search_path += (*i).path;
420 return raid_search_path.to_string ();
424 Session::setup_raid_path (string path)
433 session_dirs.clear ();
435 Searchpath search_path(path);
436 Searchpath sound_search_path;
437 Searchpath midi_search_path;
439 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
441 sp.blocks = 0; // not needed
442 session_dirs.push_back (sp);
444 SessionDirectory sdir(sp.path);
446 sound_search_path += sdir.sound_path ();
447 midi_search_path += sdir.midi_path ();
450 // reset the round-robin soundfile path thingie
451 last_rr_session_dir = session_dirs.begin();
455 Session::path_is_within_session (const std::string& path)
457 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
458 if (PBD::path_is_within (i->path, path)) {
466 Session::ensure_subdirs ()
470 dir = session_directory().peak_path();
472 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
473 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
477 dir = session_directory().sound_path();
479 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
480 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
484 dir = session_directory().midi_path();
486 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
487 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
491 dir = session_directory().dead_path();
493 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
494 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
498 dir = session_directory().export_path();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
505 dir = analysis_dir ();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
512 dir = plugins_dir ();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
519 dir = externals_dir ();
521 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
522 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
529 /** @param session_template directory containing session template, or empty.
530 * Caller must not hold process lock.
533 Session::create (const string& session_template, BusProfile* bus_profile)
535 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
536 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
540 if (ensure_subdirs ()) {
544 _writable = exists_and_writable (_path);
546 if (!session_template.empty()) {
547 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
549 FILE* in = g_fopen (in_path.c_str(), "rb");
552 /* no need to call legalize_for_path() since the string
553 * in session_template is already a legal path name
555 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
557 FILE* out = g_fopen (out_path.c_str(), "wb");
561 stringstream new_session;
564 size_t charsRead = fread (buf, sizeof(char), 1024, in);
567 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
572 if (charsRead == 0) {
575 new_session.write (buf, charsRead);
579 string file_contents = new_session.str();
580 size_t writeSize = file_contents.length();
581 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
582 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
590 if (!ARDOUR::Profile->get_trx()) {
591 /* Copy plugin state files from template to new session */
592 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
593 copy_recurse (template_plugins, plugins_dir ());
599 error << string_compose (_("Could not open %1 for writing session template"), out_path)
606 error << string_compose (_("Could not open session template %1 for reading"), in_path)
613 if (Profile->get_trx()) {
615 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
616 Remember that this is a brand new session. Sessions
617 loaded from saved state will get this range from the saved state.
620 set_session_range_location (0, 0);
622 /* Initial loop location, from absolute zero, length 10 seconds */
624 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
625 _locations->add (loc, true);
626 set_auto_loop_location (loc);
629 _state_of_the_state = Clean;
631 /* set up Master Out and Monitor Out if necessary */
636 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
638 // Waves Tracks: always create master bus for Tracks
639 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
640 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
648 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
649 r->input()->ensure_io (count, false, this);
650 r->output()->ensure_io (count, false, this);
656 /* prohibit auto-connect to master, because there isn't one */
657 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
661 add_routes (rl, false, false, false, PresentationInfo::max_order);
664 // Waves Tracks: Skip this. Always use autoconnection for Tracks
665 if (!ARDOUR::Profile->get_trx()) {
667 /* this allows the user to override settings with an environment variable.
670 if (no_auto_connect()) {
671 bus_profile->input_ac = AutoConnectOption (0);
672 bus_profile->output_ac = AutoConnectOption (0);
675 Config->set_input_auto_connect (bus_profile->input_ac);
676 Config->set_output_auto_connect (bus_profile->output_ac);
680 if (Config->get_use_monitor_bus() && bus_profile) {
681 add_monitor_section ();
688 Session::maybe_write_autosave()
690 if (dirty() && record_status() != Recording) {
691 save_state("", true);
696 Session::remove_pending_capture_state ()
698 std::string pending_state_file_path(_session_dir->root_path());
700 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
702 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
704 if (g_remove (pending_state_file_path.c_str()) != 0) {
705 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
706 pending_state_file_path, g_strerror (errno)) << endmsg;
710 /** Rename a state file.
711 * @param old_name Old snapshot name.
712 * @param new_name New snapshot name.
715 Session::rename_state (string old_name, string new_name)
717 if (old_name == _current_snapshot_name || old_name == _name) {
718 /* refuse to rename the current snapshot or the "main" one */
722 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
723 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
725 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
726 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
728 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
729 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
730 old_name, new_name, g_strerror(errno)) << endmsg;
734 /** Remove a state file.
735 * @param snapshot_name Snapshot name.
738 Session::remove_state (string snapshot_name)
740 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
741 // refuse to remove the current snapshot or the "main" one
745 std::string xml_path(_session_dir->root_path());
747 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
749 if (!create_backup_file (xml_path)) {
750 // don't remove it if a backup can't be made
751 // create_backup_file will log the error.
756 if (g_remove (xml_path.c_str()) != 0) {
757 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
758 xml_path, g_strerror (errno)) << endmsg;
762 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
764 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
766 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
769 std::string xml_path(_session_dir->root_path());
771 /* prevent concurrent saves from different threads */
773 Glib::Threads::Mutex::Lock lm (save_state_lock);
775 if (!_writable || (_state_of_the_state & CannotSave)) {
779 if (g_atomic_int_get(&_suspend_save)) {
783 _save_queued = false;
785 if (!_engine.connected ()) {
786 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
793 const int64_t save_start_time = g_get_monotonic_time();
796 /* tell sources we're saving first, in case they write out to a new file
797 * which should be saved with the state rather than the old one */
798 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
800 i->second->session_saved();
801 } catch (Evoral::SMF::FileError& e) {
802 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
806 SessionSaveUnderway (); /* EMIT SIGNAL */
808 bool mark_as_clean = true;
810 if (!snapshot_name.empty() && !switch_to_snapshot) {
811 mark_as_clean = false;
815 mark_as_clean = false;
816 tree.set_root (&get_template());
818 tree.set_root (&get_state());
821 if (snapshot_name.empty()) {
822 snapshot_name = _current_snapshot_name;
823 } else if (switch_to_snapshot) {
824 set_snapshot_name (snapshot_name);
827 assert (!snapshot_name.empty());
831 /* proper save: use statefile_suffix (.ardour in English) */
833 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
835 /* make a backup copy of the old file */
837 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
838 // create_backup_file will log the error
844 /* pending save: use pending_suffix (.pending in English) */
845 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
848 std::string tmp_path(_session_dir->root_path());
849 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
851 cerr << "actually writing state to " << tmp_path << endl;
853 if (!tree.write (tmp_path)) {
854 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
855 if (g_remove (tmp_path.c_str()) != 0) {
856 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
857 tmp_path, g_strerror (errno)) << endmsg;
863 cerr << "renaming state to " << xml_path << endl;
865 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
866 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
867 tmp_path, xml_path, g_strerror(errno)) << endmsg;
868 if (g_remove (tmp_path.c_str()) != 0) {
869 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
870 tmp_path, g_strerror (errno)) << endmsg;
878 save_history (snapshot_name);
881 bool was_dirty = dirty();
883 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
886 DirtyChanged (); /* EMIT SIGNAL */
890 StateSaved (snapshot_name); /* EMIT SIGNAL */
894 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
895 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
901 Session::restore_state (string snapshot_name)
903 if (load_state (snapshot_name) == 0) {
904 set_state (*state_tree->root(), Stateful::loading_state_version);
911 Session::load_state (string snapshot_name)
916 state_was_pending = false;
918 /* check for leftover pending state from a crashed capture attempt */
920 std::string xmlpath(_session_dir->root_path());
921 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
923 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
925 /* there is pending state from a crashed capture attempt */
927 boost::optional<int> r = AskAboutPendingState();
928 if (r.get_value_or (1)) {
929 state_was_pending = true;
933 if (!state_was_pending) {
934 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
937 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
938 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
939 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
945 state_tree = new XMLTree;
949 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
951 if (!state_tree->read (xmlpath)) {
952 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
958 XMLNode const & root (*state_tree->root());
960 if (root.name() != X_("Session")) {
961 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
967 XMLProperty const * prop;
969 if ((prop = root.property ("version")) == 0) {
970 /* no version implies very old version of Ardour */
971 Stateful::loading_state_version = 1000;
973 if (prop->value().find ('.') != string::npos) {
974 /* old school version format */
975 if (prop->value()[0] == '2') {
976 Stateful::loading_state_version = 2000;
978 Stateful::loading_state_version = 3000;
981 Stateful::loading_state_version = atoi (prop->value());
985 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
987 std::string backup_path(_session_dir->root_path());
988 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
989 backup_path = Glib::build_filename (backup_path, backup_filename);
991 // only create a backup for a given statefile version once
993 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
995 VersionMismatch (xmlpath, backup_path);
997 if (!copy_file (xmlpath, backup_path)) {;
1003 save_snapshot_name (snapshot_name);
1009 Session::load_options (const XMLNode& node)
1012 config.set_variables (node);
1017 Session::save_default_options ()
1019 return config.save_state();
1023 Session::get_state()
1029 Session::get_template()
1031 /* if we don't disable rec-enable, diskstreams
1032 will believe they need to store their capture
1033 sources in their state node.
1036 disable_record (false);
1038 return state(false);
1042 Session::state (bool full_state)
1045 XMLNode* node = new XMLNode("Session");
1049 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1050 node->add_property("version", buf);
1052 /* store configuration settings */
1056 node->add_property ("name", _name);
1057 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1058 node->add_property ("sample-rate", buf);
1060 if (session_dirs.size() > 1) {
1064 vector<space_and_path>::iterator i = session_dirs.begin();
1065 vector<space_and_path>::iterator next;
1067 ++i; /* skip the first one */
1071 while (i != session_dirs.end()) {
1075 if (next != session_dirs.end()) {
1076 p += G_SEARCHPATH_SEPARATOR;
1085 child = node->add_child ("Path");
1086 child->add_content (p);
1090 /* save the ID counter */
1092 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1093 node->add_property ("id-counter", buf);
1095 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1096 node->add_property ("name-counter", buf);
1098 /* save the event ID counter */
1100 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1101 node->add_property ("event-counter", buf);
1103 /* save the VCA counter */
1105 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1106 node->add_property ("vca-counter", buf);
1108 /* various options */
1110 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1111 if (!midi_port_nodes.empty()) {
1112 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1113 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1114 midi_port_stuff->add_child_nocopy (**n);
1116 node->add_child_nocopy (*midi_port_stuff);
1119 node->add_child_nocopy (config.get_variables ());
1121 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1123 child = node->add_child ("Sources");
1126 Glib::Threads::Mutex::Lock sl (source_lock);
1128 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1130 /* Don't save information about non-file Sources, or
1131 * about non-destructive file sources that are empty
1132 * and unused by any regions.
1135 boost::shared_ptr<FileSource> fs;
1137 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1139 if (!fs->destructive()) {
1140 if (fs->empty() && !fs->used()) {
1145 child->add_child_nocopy (siter->second->get_state());
1150 child = node->add_child ("Regions");
1153 Glib::Threads::Mutex::Lock rl (region_lock);
1154 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1155 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1156 boost::shared_ptr<Region> r = i->second;
1157 /* only store regions not attached to playlists */
1158 if (r->playlist() == 0) {
1159 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1160 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1162 child->add_child_nocopy (r->get_state ());
1167 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1169 if (!cassocs.empty()) {
1170 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1172 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1174 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1175 i->first->id().print (buf, sizeof (buf));
1176 can->add_property (X_("copy"), buf);
1177 i->second->id().print (buf, sizeof (buf));
1178 can->add_property (X_("original"), buf);
1179 ca->add_child_nocopy (*can);
1189 node->add_child_nocopy (_locations->get_state());
1192 Locations loc (*this);
1193 // for a template, just create a new Locations, populate it
1194 // with the default start and end, and get the state for that.
1195 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1196 range->set (max_framepos, 0);
1198 XMLNode& locations_state = loc.get_state();
1200 if (ARDOUR::Profile->get_trx() && _locations) {
1201 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1202 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1203 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1204 locations_state.add_child_nocopy ((*i)->get_state ());
1208 node->add_child_nocopy (locations_state);
1211 child = node->add_child ("Bundles");
1213 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1214 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1215 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1217 child->add_child_nocopy (b->get_state());
1222 node->add_child_nocopy (_vca_manager->get_state());
1224 child = node->add_child ("Routes");
1226 boost::shared_ptr<RouteList> r = routes.reader ();
1228 RoutePublicOrderSorter cmp;
1229 RouteList public_order (*r);
1230 public_order.sort (cmp);
1232 /* the sort should have put control outs first */
1235 assert (_monitor_out == public_order.front());
1238 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1239 if (!(*i)->is_auditioner()) {
1241 child->add_child_nocopy ((*i)->get_state());
1243 child->add_child_nocopy ((*i)->get_template());
1249 playlists->add_state (node, full_state);
1251 child = node->add_child ("RouteGroups");
1252 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1253 child->add_child_nocopy ((*i)->get_state());
1257 XMLNode* gain_child = node->add_child ("Click");
1258 gain_child->add_child_nocopy (_click_io->state (full_state));
1259 gain_child->add_child_nocopy (_click_gain->state (full_state));
1263 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1264 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1268 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1269 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1272 node->add_child_nocopy (_speakers->get_state());
1273 node->add_child_nocopy (_tempo_map->get_state());
1274 node->add_child_nocopy (get_control_protocol_state());
1277 node->add_child_copy (*_extra_xml);
1281 Glib::Threads::Mutex::Lock lm (lua_lock);
1284 luabridge::LuaRef savedstate ((*_lua_save)());
1285 saved = savedstate.cast<std::string>();
1287 lua.collect_garbage ();
1290 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1291 std::string b64s (b64);
1294 XMLNode* script_node = new XMLNode (X_("Script"));
1295 script_node->add_property (X_("lua"), LUA_VERSION);
1296 script_node->add_content (b64s);
1297 node->add_child_nocopy (*script_node);
1304 Session::get_control_protocol_state ()
1306 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1307 return cpm.get_state();
1311 Session::set_state (const XMLNode& node, int version)
1316 XMLProperty const * prop;
1319 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1321 if (node.name() != X_("Session")) {
1322 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1326 if ((prop = node.property ("name")) != 0) {
1327 _name = prop->value ();
1330 if ((prop = node.property (X_("sample-rate"))) != 0) {
1332 _base_frame_rate = atoi (prop->value());
1333 _nominal_frame_rate = _base_frame_rate;
1335 assert (AudioEngine::instance()->running ());
1336 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1337 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1338 if (r.get_value_or (0)) {
1344 setup_raid_path(_session_dir->root_path());
1346 if ((prop = node.property (X_("id-counter"))) != 0) {
1348 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1349 ID::init_counter (x);
1351 /* old sessions used a timebased counter, so fake
1352 the startup ID counter based on a standard
1357 ID::init_counter (now);
1360 if ((prop = node.property (X_("name-counter"))) != 0) {
1361 init_name_id_counter (atoi (prop->value()));
1364 if ((prop = node.property (X_("event-counter"))) != 0) {
1365 Evoral::init_event_id_counter (atoi (prop->value()));
1368 if ((prop = node.property (X_("vca-counter"))) != 0) {
1370 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1371 VCA::set_next_vca_number (x);
1373 VCA::set_next_vca_number (1);
1376 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1377 _midi_ports->set_midi_port_states (child->children());
1380 IO::disable_connecting ();
1382 Stateful::save_extra_xml (node);
1384 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1385 load_options (*child);
1386 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1387 load_options (*child);
1389 error << _("Session: XML state has no options section") << endmsg;
1392 if (version >= 3000) {
1393 if ((child = find_named_node (node, "Metadata")) == 0) {
1394 warning << _("Session: XML state has no metadata section") << endmsg;
1395 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1400 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1401 _speakers->set_state (*child, version);
1404 if ((child = find_named_node (node, "Sources")) == 0) {
1405 error << _("Session: XML state has no sources section") << endmsg;
1407 } else if (load_sources (*child)) {
1411 if ((child = find_named_node (node, "TempoMap")) == 0) {
1412 error << _("Session: XML state has no Tempo Map section") << endmsg;
1414 } else if (_tempo_map->set_state (*child, version)) {
1418 if ((child = find_named_node (node, "Locations")) == 0) {
1419 error << _("Session: XML state has no locations section") << endmsg;
1421 } else if (_locations->set_state (*child, version)) {
1425 locations_changed ();
1427 if (_session_range_location) {
1428 AudioFileSource::set_header_position_offset (_session_range_location->start());
1431 if ((child = find_named_node (node, "Regions")) == 0) {
1432 error << _("Session: XML state has no Regions section") << endmsg;
1434 } else if (load_regions (*child)) {
1438 if ((child = find_named_node (node, "Playlists")) == 0) {
1439 error << _("Session: XML state has no playlists section") << endmsg;
1441 } else if (playlists->load (*this, *child)) {
1445 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1447 } else if (playlists->load_unused (*this, *child)) {
1451 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1452 if (load_compounds (*child)) {
1457 if (version >= 3000) {
1458 if ((child = find_named_node (node, "Bundles")) == 0) {
1459 warning << _("Session: XML state has no bundles section") << endmsg;
1462 /* We can't load Bundles yet as they need to be able
1463 to convert from port names to Port objects, which can't happen until
1465 _bundle_xml_node = new XMLNode (*child);
1469 if (version < 3000) {
1470 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1471 error << _("Session: XML state has no diskstreams section") << endmsg;
1473 } else if (load_diskstreams_2X (*child, version)) {
1478 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1479 _vca_manager->set_state (*child, version);
1482 if ((child = find_named_node (node, "Routes")) == 0) {
1483 error << _("Session: XML state has no routes section") << endmsg;
1485 } else if (load_routes (*child, version)) {
1489 /* Now that we have Routes and masters loaded, connect them if appropriate */
1491 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1493 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1494 _diskstreams_2X.clear ();
1496 if (version >= 3000) {
1498 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1499 error << _("Session: XML state has no route groups section") << endmsg;
1501 } else if (load_route_groups (*child, version)) {
1505 } else if (version < 3000) {
1507 if ((child = find_named_node (node, "EditGroups")) == 0) {
1508 error << _("Session: XML state has no edit groups section") << endmsg;
1510 } else if (load_route_groups (*child, version)) {
1514 if ((child = find_named_node (node, "MixGroups")) == 0) {
1515 error << _("Session: XML state has no mix groups section") << endmsg;
1517 } else if (load_route_groups (*child, version)) {
1522 if ((child = find_named_node (node, "Click")) == 0) {
1523 warning << _("Session: XML state has no click section") << endmsg;
1524 } else if (_click_io) {
1525 setup_click_state (&node);
1528 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1529 ControlProtocolManager::instance().set_state (*child, version);
1532 if ((child = find_named_node (node, "Script"))) {
1533 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1534 if (!(*n)->is_content ()) { continue; }
1536 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1538 Glib::Threads::Mutex::Lock lm (lua_lock);
1539 (*_lua_load)(std::string ((const char*)buf, size));
1540 } catch (luabridge::LuaException const& e) {
1541 cerr << "LuaException:" << e.what () << endl;
1547 update_route_record_state ();
1549 /* here beginneth the second phase ... */
1550 set_snapshot_name (_current_snapshot_name);
1552 StateReady (); /* EMIT SIGNAL */
1565 Session::load_routes (const XMLNode& node, int version)
1568 XMLNodeConstIterator niter;
1569 RouteList new_routes;
1571 nlist = node.children();
1575 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1577 boost::shared_ptr<Route> route;
1578 if (version < 3000) {
1579 route = XMLRouteFactory_2X (**niter, version);
1581 route = XMLRouteFactory (**niter, version);
1585 error << _("Session: cannot create Route from XML description.") << endmsg;
1589 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1591 new_routes.push_back (route);
1594 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1596 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1598 BootMessage (_("Finished adding tracks/busses"));
1600 boost::shared_ptr<Route> r;
1601 uint32_t n = nroutes ();
1603 for (uint32_t nn = 0; nn < n + 1; ++nn) {
1604 r = get_remote_nth_route (nn);
1606 std::cerr << "Nth-route = " << r->name() << endl;
1608 std::cerr << "Nth-route: undefined\n";
1612 boost::shared_ptr<Stripable> s;
1613 s = get_remote_nth_stripable (0, PresentationInfo::MasterOut);
1614 std::cerr << " Master = " << s << std::endl;
1615 s = get_remote_nth_stripable (0, PresentationInfo::MonitorOut);
1616 std::cerr << " Monitor = " << s << std::endl;
1621 boost::shared_ptr<Route>
1622 Session::XMLRouteFactory (const XMLNode& node, int version)
1624 boost::shared_ptr<Route> ret;
1626 if (node.name() != "Route") {
1630 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1632 DataType type = DataType::AUDIO;
1633 XMLProperty const * prop = node.property("default-type");
1636 type = DataType (prop->value());
1639 assert (type != DataType::NIL);
1643 boost::shared_ptr<Track> track;
1645 if (type == DataType::AUDIO) {
1646 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1648 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1651 if (track->init()) {
1655 if (track->set_state (node, version)) {
1659 BOOST_MARK_TRACK (track);
1663 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1664 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1666 if (r->init () == 0 && r->set_state (node, version) == 0) {
1667 BOOST_MARK_ROUTE (r);
1675 boost::shared_ptr<Route>
1676 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1678 boost::shared_ptr<Route> ret;
1680 if (node.name() != "Route") {
1684 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1686 ds_prop = node.property (X_("diskstream"));
1689 DataType type = DataType::AUDIO;
1690 XMLProperty const * prop = node.property("default-type");
1693 type = DataType (prop->value());
1696 assert (type != DataType::NIL);
1700 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1701 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1705 if (i == _diskstreams_2X.end()) {
1706 error << _("Could not find diskstream for route") << endmsg;
1707 return boost::shared_ptr<Route> ();
1710 boost::shared_ptr<Track> track;
1712 if (type == DataType::AUDIO) {
1713 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1715 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1718 if (track->init()) {
1722 if (track->set_state (node, version)) {
1726 track->set_diskstream (*i);
1728 BOOST_MARK_TRACK (track);
1732 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1733 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1735 if (r->init () == 0 && r->set_state (node, version) == 0) {
1736 BOOST_MARK_ROUTE (r);
1745 Session::load_regions (const XMLNode& node)
1748 XMLNodeConstIterator niter;
1749 boost::shared_ptr<Region> region;
1751 nlist = node.children();
1755 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1756 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1757 error << _("Session: cannot create Region from XML description.");
1758 XMLProperty const * name = (**niter).property("name");
1761 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1772 Session::load_compounds (const XMLNode& node)
1774 XMLNodeList calist = node.children();
1775 XMLNodeConstIterator caiter;
1776 XMLProperty const * caprop;
1778 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1779 XMLNode* ca = *caiter;
1783 if ((caprop = ca->property (X_("original"))) == 0) {
1786 orig_id = caprop->value();
1788 if ((caprop = ca->property (X_("copy"))) == 0) {
1791 copy_id = caprop->value();
1793 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1794 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1796 if (!orig || !copy) {
1797 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1803 RegionFactory::add_compound_association (orig, copy);
1810 Session::load_nested_sources (const XMLNode& node)
1813 XMLNodeConstIterator niter;
1815 nlist = node.children();
1817 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1818 if ((*niter)->name() == "Source") {
1820 /* it may already exist, so don't recreate it unnecessarily
1823 XMLProperty const * prop = (*niter)->property (X_("id"));
1825 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1829 ID source_id (prop->value());
1831 if (!source_by_id (source_id)) {
1834 SourceFactory::create (*this, **niter, true);
1836 catch (failed_constructor& err) {
1837 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1844 boost::shared_ptr<Region>
1845 Session::XMLRegionFactory (const XMLNode& node, bool full)
1847 XMLProperty const * type = node.property("type");
1851 const XMLNodeList& nlist = node.children();
1853 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1854 XMLNode *child = (*niter);
1855 if (child->name() == "NestedSource") {
1856 load_nested_sources (*child);
1860 if (!type || type->value() == "audio") {
1861 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1862 } else if (type->value() == "midi") {
1863 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1866 } catch (failed_constructor& err) {
1867 return boost::shared_ptr<Region> ();
1870 return boost::shared_ptr<Region> ();
1873 boost::shared_ptr<AudioRegion>
1874 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1876 XMLProperty const * prop;
1877 boost::shared_ptr<Source> source;
1878 boost::shared_ptr<AudioSource> as;
1880 SourceList master_sources;
1881 uint32_t nchans = 1;
1884 if (node.name() != X_("Region")) {
1885 return boost::shared_ptr<AudioRegion>();
1888 if ((prop = node.property (X_("channels"))) != 0) {
1889 nchans = atoi (prop->value().c_str());
1892 if ((prop = node.property ("name")) == 0) {
1893 cerr << "no name for this region\n";
1897 if ((prop = node.property (X_("source-0"))) == 0) {
1898 if ((prop = node.property ("source")) == 0) {
1899 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1900 return boost::shared_ptr<AudioRegion>();
1904 PBD::ID s_id (prop->value());
1906 if ((source = source_by_id (s_id)) == 0) {
1907 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1908 return boost::shared_ptr<AudioRegion>();
1911 as = boost::dynamic_pointer_cast<AudioSource>(source);
1913 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1914 return boost::shared_ptr<AudioRegion>();
1917 sources.push_back (as);
1919 /* pickup other channels */
1921 for (uint32_t n=1; n < nchans; ++n) {
1922 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1923 if ((prop = node.property (buf)) != 0) {
1925 PBD::ID id2 (prop->value());
1927 if ((source = source_by_id (id2)) == 0) {
1928 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1929 return boost::shared_ptr<AudioRegion>();
1932 as = boost::dynamic_pointer_cast<AudioSource>(source);
1934 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1935 return boost::shared_ptr<AudioRegion>();
1937 sources.push_back (as);
1941 for (uint32_t n = 0; n < nchans; ++n) {
1942 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1943 if ((prop = node.property (buf)) != 0) {
1945 PBD::ID id2 (prop->value());
1947 if ((source = source_by_id (id2)) == 0) {
1948 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1949 return boost::shared_ptr<AudioRegion>();
1952 as = boost::dynamic_pointer_cast<AudioSource>(source);
1954 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1955 return boost::shared_ptr<AudioRegion>();
1957 master_sources.push_back (as);
1962 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1964 /* a final detail: this is the one and only place that we know how long missing files are */
1966 if (region->whole_file()) {
1967 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1968 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1970 sfp->set_length (region->length());
1975 if (!master_sources.empty()) {
1976 if (master_sources.size() != nchans) {
1977 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1979 region->set_master_sources (master_sources);
1987 catch (failed_constructor& err) {
1988 return boost::shared_ptr<AudioRegion>();
1992 boost::shared_ptr<MidiRegion>
1993 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1995 XMLProperty const * prop;
1996 boost::shared_ptr<Source> source;
1997 boost::shared_ptr<MidiSource> ms;
2000 if (node.name() != X_("Region")) {
2001 return boost::shared_ptr<MidiRegion>();
2004 if ((prop = node.property ("name")) == 0) {
2005 cerr << "no name for this region\n";
2009 if ((prop = node.property (X_("source-0"))) == 0) {
2010 if ((prop = node.property ("source")) == 0) {
2011 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2012 return boost::shared_ptr<MidiRegion>();
2016 PBD::ID s_id (prop->value());
2018 if ((source = source_by_id (s_id)) == 0) {
2019 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2020 return boost::shared_ptr<MidiRegion>();
2023 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2025 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2026 return boost::shared_ptr<MidiRegion>();
2029 sources.push_back (ms);
2032 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2033 /* a final detail: this is the one and only place that we know how long missing files are */
2035 if (region->whole_file()) {
2036 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2037 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2039 sfp->set_length (region->length());
2047 catch (failed_constructor& err) {
2048 return boost::shared_ptr<MidiRegion>();
2053 Session::get_sources_as_xml ()
2056 XMLNode* node = new XMLNode (X_("Sources"));
2057 Glib::Threads::Mutex::Lock lm (source_lock);
2059 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2060 node->add_child_nocopy (i->second->get_state());
2067 Session::reset_write_sources (bool mark_write_complete, bool force)
2069 boost::shared_ptr<RouteList> rl = routes.reader();
2070 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2071 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2073 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2074 tr->reset_write_sources(mark_write_complete, force);
2075 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2081 Session::load_sources (const XMLNode& node)
2084 XMLNodeConstIterator niter;
2085 boost::shared_ptr<Source> source; /* don't need this but it stops some
2086 * versions of gcc complaining about
2087 * discarded return values.
2090 nlist = node.children();
2094 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2097 if ((source = XMLSourceFactory (**niter)) == 0) {
2098 error << _("Session: cannot create Source from XML description.") << endmsg;
2101 } catch (MissingSource& err) {
2105 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2106 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2107 PROGRAM_NAME) << endmsg;
2111 if (!no_questions_about_missing_files) {
2112 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2117 switch (user_choice) {
2119 /* user added a new search location, so try again */
2124 /* user asked to quit the entire session load
2129 no_questions_about_missing_files = true;
2133 no_questions_about_missing_files = true;
2140 case DataType::AUDIO:
2141 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2144 case DataType::MIDI:
2145 /* The MIDI file is actually missing so
2146 * just create a new one in the same
2147 * location. Do not announce its
2151 if (!Glib::path_is_absolute (err.path)) {
2152 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2154 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2159 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2160 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2161 /* reset ID to match the missing one */
2162 source->set_id (**niter);
2163 /* Now we can announce it */
2164 SourceFactory::SourceCreated (source);
2175 boost::shared_ptr<Source>
2176 Session::XMLSourceFactory (const XMLNode& node)
2178 if (node.name() != "Source") {
2179 return boost::shared_ptr<Source>();
2183 /* note: do peak building in another thread when loading session state */
2184 return SourceFactory::create (*this, node, true);
2187 catch (failed_constructor& err) {
2188 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2189 return boost::shared_ptr<Source>();
2194 Session::save_template (string template_name, bool replace_existing)
2196 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2200 bool absolute_path = Glib::path_is_absolute (template_name);
2202 /* directory to put the template in */
2203 std::string template_dir_path;
2205 if (!absolute_path) {
2206 std::string user_template_dir(user_template_directory());
2208 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2209 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2210 user_template_dir, g_strerror (errno)) << endmsg;
2214 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2216 template_dir_path = template_name;
2219 if (!ARDOUR::Profile->get_trx()) {
2220 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2221 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2222 template_dir_path) << endmsg;
2226 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2227 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2228 template_dir_path, g_strerror (errno)) << endmsg;
2234 std::string template_file_path;
2236 if (ARDOUR::Profile->get_trx()) {
2237 template_file_path = template_name;
2239 if (absolute_path) {
2240 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2242 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2246 SessionSaveUnderway (); /* EMIT SIGNAL */
2251 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2252 tree.set_root (&get_template());
2255 if (!tree.write (template_file_path)) {
2256 error << _("template not saved") << endmsg;
2260 store_recent_templates (template_file_path);
2266 Session::refresh_disk_space ()
2268 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2270 Glib::Threads::Mutex::Lock lm (space_lock);
2272 /* get freespace on every FS that is part of the session path */
2274 _total_free_4k_blocks = 0;
2275 _total_free_4k_blocks_uncertain = false;
2277 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2279 struct statfs statfsbuf;
2280 statfs (i->path.c_str(), &statfsbuf);
2282 double const scale = statfsbuf.f_bsize / 4096.0;
2284 /* See if this filesystem is read-only */
2285 struct statvfs statvfsbuf;
2286 statvfs (i->path.c_str(), &statvfsbuf);
2288 /* f_bavail can be 0 if it is undefined for whatever
2289 filesystem we are looking at; Samba shares mounted
2290 via GVFS are an example of this.
2292 if (statfsbuf.f_bavail == 0) {
2293 /* block count unknown */
2295 i->blocks_unknown = true;
2296 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2297 /* read-only filesystem */
2299 i->blocks_unknown = false;
2301 /* read/write filesystem with known space */
2302 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2303 i->blocks_unknown = false;
2306 _total_free_4k_blocks += i->blocks;
2307 if (i->blocks_unknown) {
2308 _total_free_4k_blocks_uncertain = true;
2311 #elif defined PLATFORM_WINDOWS
2312 vector<string> scanned_volumes;
2313 vector<string>::iterator j;
2314 vector<space_and_path>::iterator i;
2315 DWORD nSectorsPerCluster, nBytesPerSector,
2316 nFreeClusters, nTotalClusters;
2320 _total_free_4k_blocks = 0;
2322 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2323 strncpy (disk_drive, (*i).path.c_str(), 3);
2327 volume_found = false;
2328 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2330 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2331 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2332 i->blocks = (uint32_t)(nFreeBytes / 4096);
2334 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2335 if (0 == j->compare(disk_drive)) {
2336 volume_found = true;
2341 if (!volume_found) {
2342 scanned_volumes.push_back(disk_drive);
2343 _total_free_4k_blocks += i->blocks;
2348 if (0 == _total_free_4k_blocks) {
2349 strncpy (disk_drive, path().c_str(), 3);
2352 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2354 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2355 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2356 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2363 Session::get_best_session_directory_for_new_audio ()
2365 vector<space_and_path>::iterator i;
2366 string result = _session_dir->root_path();
2368 /* handle common case without system calls */
2370 if (session_dirs.size() == 1) {
2374 /* OK, here's the algorithm we're following here:
2376 We want to select which directory to use for
2377 the next file source to be created. Ideally,
2378 we'd like to use a round-robin process so as to
2379 get maximum performance benefits from splitting
2380 the files across multiple disks.
2382 However, in situations without much diskspace, an
2383 RR approach may end up filling up a filesystem
2384 with new files while others still have space.
2385 Its therefore important to pay some attention to
2386 the freespace in the filesystem holding each
2387 directory as well. However, if we did that by
2388 itself, we'd keep creating new files in the file
2389 system with the most space until it was as full
2390 as all others, thus negating any performance
2391 benefits of this RAID-1 like approach.
2393 So, we use a user-configurable space threshold. If
2394 there are at least 2 filesystems with more than this
2395 much space available, we use RR selection between them.
2396 If not, then we pick the filesystem with the most space.
2398 This gets a good balance between the two
2402 refresh_disk_space ();
2404 int free_enough = 0;
2406 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2407 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2412 if (free_enough >= 2) {
2413 /* use RR selection process, ensuring that the one
2417 i = last_rr_session_dir;
2420 if (++i == session_dirs.end()) {
2421 i = session_dirs.begin();
2424 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2425 SessionDirectory sdir(i->path);
2426 if (sdir.create ()) {
2428 last_rr_session_dir = i;
2433 } while (i != last_rr_session_dir);
2437 /* pick FS with the most freespace (and that
2438 seems to actually work ...)
2441 vector<space_and_path> sorted;
2442 space_and_path_ascending_cmp cmp;
2444 sorted = session_dirs;
2445 sort (sorted.begin(), sorted.end(), cmp);
2447 for (i = sorted.begin(); i != sorted.end(); ++i) {
2448 SessionDirectory sdir(i->path);
2449 if (sdir.create ()) {
2451 last_rr_session_dir = i;
2461 Session::automation_dir () const
2463 return Glib::build_filename (_path, automation_dir_name);
2467 Session::analysis_dir () const
2469 return Glib::build_filename (_path, analysis_dir_name);
2473 Session::plugins_dir () const
2475 return Glib::build_filename (_path, plugins_dir_name);
2479 Session::externals_dir () const
2481 return Glib::build_filename (_path, externals_dir_name);
2485 Session::load_bundles (XMLNode const & node)
2487 XMLNodeList nlist = node.children();
2488 XMLNodeConstIterator niter;
2492 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2493 if ((*niter)->name() == "InputBundle") {
2494 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2495 } else if ((*niter)->name() == "OutputBundle") {
2496 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2498 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2507 Session::load_route_groups (const XMLNode& node, int version)
2509 XMLNodeList nlist = node.children();
2510 XMLNodeConstIterator niter;
2514 if (version >= 3000) {
2516 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2517 if ((*niter)->name() == "RouteGroup") {
2518 RouteGroup* rg = new RouteGroup (*this, "");
2519 add_route_group (rg);
2520 rg->set_state (**niter, version);
2524 } else if (version < 3000) {
2526 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2527 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2528 RouteGroup* rg = new RouteGroup (*this, "");
2529 add_route_group (rg);
2530 rg->set_state (**niter, version);
2539 state_file_filter (const string &str, void* /*arg*/)
2541 return (str.length() > strlen(statefile_suffix) &&
2542 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2546 remove_end(string state)
2548 string statename(state);
2550 string::size_type start,end;
2551 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2552 statename = statename.substr (start+1);
2555 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2556 end = statename.length();
2559 return string(statename.substr (0, end));
2563 Session::possible_states (string path)
2565 vector<string> states;
2566 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2568 transform(states.begin(), states.end(), states.begin(), remove_end);
2570 sort (states.begin(), states.end());
2576 Session::possible_states () const
2578 return possible_states(_path);
2582 Session::add_route_group (RouteGroup* g)
2584 _route_groups.push_back (g);
2585 route_group_added (g); /* EMIT SIGNAL */
2587 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2588 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2589 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2595 Session::remove_route_group (RouteGroup& rg)
2597 list<RouteGroup*>::iterator i;
2599 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2600 _route_groups.erase (i);
2603 route_group_removed (); /* EMIT SIGNAL */
2607 /** Set a new order for our route groups, without adding or removing any.
2608 * @param groups Route group list in the new order.
2611 Session::reorder_route_groups (list<RouteGroup*> groups)
2613 _route_groups = groups;
2615 route_groups_reordered (); /* EMIT SIGNAL */
2621 Session::route_group_by_name (string name)
2623 list<RouteGroup *>::iterator i;
2625 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2626 if ((*i)->name() == name) {
2634 Session::all_route_group() const
2636 return *_all_route_group;
2640 Session::add_commands (vector<Command*> const & cmds)
2642 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2648 Session::add_command (Command* const cmd)
2650 assert (_current_trans);
2651 DEBUG_UNDO_HISTORY (
2652 string_compose ("Current Undo Transaction %1, adding command: %2",
2653 _current_trans->name (),
2655 _current_trans->add_command (cmd);
2658 PBD::StatefulDiffCommand*
2659 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2661 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2667 Session::begin_reversible_command (const string& name)
2669 begin_reversible_command (g_quark_from_string (name.c_str ()));
2672 /** Begin a reversible command using a GQuark to identify it.
2673 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2674 * but there must be as many begin...()s as there are commit...()s.
2677 Session::begin_reversible_command (GQuark q)
2679 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2680 to hold all the commands that are committed. This keeps the order of
2681 commands correct in the history.
2684 if (_current_trans == 0) {
2685 DEBUG_UNDO_HISTORY (string_compose (
2686 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2688 /* start a new transaction */
2689 assert (_current_trans_quarks.empty ());
2690 _current_trans = new UndoTransaction();
2691 _current_trans->set_name (g_quark_to_string (q));
2693 DEBUG_UNDO_HISTORY (
2694 string_compose ("Begin Reversible Command, current transaction: %1",
2695 _current_trans->name ()));
2698 _current_trans_quarks.push_front (q);
2702 Session::abort_reversible_command ()
2704 if (_current_trans != 0) {
2705 DEBUG_UNDO_HISTORY (
2706 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2707 _current_trans->clear();
2708 delete _current_trans;
2710 _current_trans_quarks.clear();
2715 Session::commit_reversible_command (Command *cmd)
2717 assert (_current_trans);
2718 assert (!_current_trans_quarks.empty ());
2723 DEBUG_UNDO_HISTORY (
2724 string_compose ("Current Undo Transaction %1, adding command: %2",
2725 _current_trans->name (),
2727 _current_trans->add_command (cmd);
2730 DEBUG_UNDO_HISTORY (
2731 string_compose ("Commit Reversible Command, current transaction: %1",
2732 _current_trans->name ()));
2734 _current_trans_quarks.pop_front ();
2736 if (!_current_trans_quarks.empty ()) {
2737 DEBUG_UNDO_HISTORY (
2738 string_compose ("Commit Reversible Command, transaction is not "
2739 "top-level, current transaction: %1",
2740 _current_trans->name ()));
2741 /* the transaction we're committing is not the top-level one */
2745 if (_current_trans->empty()) {
2746 /* no commands were added to the transaction, so just get rid of it */
2747 DEBUG_UNDO_HISTORY (
2748 string_compose ("Commit Reversible Command, No commands were "
2749 "added to current transaction: %1",
2750 _current_trans->name ()));
2751 delete _current_trans;
2756 gettimeofday (&now, 0);
2757 _current_trans->set_timestamp (now);
2759 _history.add (_current_trans);
2764 accept_all_audio_files (const string& path, void* /*arg*/)
2766 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2770 if (!AudioFileSource::safe_audio_file_extension (path)) {
2778 accept_all_midi_files (const string& path, void* /*arg*/)
2780 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2784 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2785 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2786 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2790 accept_all_state_files (const string& path, void* /*arg*/)
2792 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2796 std::string const statefile_ext (statefile_suffix);
2797 if (path.length() >= statefile_ext.length()) {
2798 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2805 Session::find_all_sources (string path, set<string>& result)
2810 if (!tree.read (path)) {
2814 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2819 XMLNodeConstIterator niter;
2821 nlist = node->children();
2825 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2827 XMLProperty const * prop;
2829 if ((prop = (*niter)->property (X_("type"))) == 0) {
2833 DataType type (prop->value());
2835 if ((prop = (*niter)->property (X_("name"))) == 0) {
2839 if (Glib::path_is_absolute (prop->value())) {
2840 /* external file, ignore */
2848 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2849 result.insert (found_path);
2857 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2859 vector<string> state_files;
2861 string this_snapshot_path;
2867 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2868 ripped = ripped.substr (0, ripped.length() - 1);
2871 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2873 if (state_files.empty()) {
2878 this_snapshot_path = _path;
2879 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2880 this_snapshot_path += statefile_suffix;
2882 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2884 if (exclude_this_snapshot && *i == this_snapshot_path) {
2888 if (find_all_sources (*i, result) < 0) {
2896 struct RegionCounter {
2897 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2898 AudioSourceList::iterator iter;
2899 boost::shared_ptr<Region> region;
2902 RegionCounter() : count (0) {}
2906 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2908 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2909 return r.get_value_or (1);
2913 Session::cleanup_regions ()
2915 bool removed = false;
2916 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2918 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2920 uint32_t used = playlists->region_use_count (i->second);
2922 if (used == 0 && !i->second->automatic ()) {
2923 boost::weak_ptr<Region> w = i->second;
2926 RegionFactory::map_remove (w);
2933 // re-check to remove parent references of compound regions
2934 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2935 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2939 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2940 if (0 == playlists->region_use_count (i->second)) {
2941 boost::weak_ptr<Region> w = i->second;
2943 RegionFactory::map_remove (w);
2950 /* dump the history list */
2957 Session::can_cleanup_peakfiles () const
2959 if (deletion_in_progress()) {
2962 if (!_writable || (_state_of_the_state & CannotSave)) {
2963 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2966 if (record_status() == Recording) {
2967 error << _("Cannot cleanup peak-files while recording") << endmsg;
2974 Session::cleanup_peakfiles ()
2976 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2981 assert (can_cleanup_peakfiles ());
2982 assert (!peaks_cleanup_in_progres());
2984 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2986 int timeout = 5000; // 5 seconds
2987 while (!SourceFactory::files_with_peaks.empty()) {
2988 Glib::usleep (1000);
2989 if (--timeout < 0) {
2990 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2991 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2996 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2997 boost::shared_ptr<AudioSource> as;
2998 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2999 as->close_peakfile();
3003 PBD::clear_directory (session_directory().peak_path());
3005 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3007 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3008 boost::shared_ptr<AudioSource> as;
3009 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3010 SourceFactory::setup_peakfile(as, true);
3017 Session::cleanup_sources (CleanupReport& rep)
3019 // FIXME: needs adaptation to midi
3021 vector<boost::shared_ptr<Source> > dead_sources;
3024 vector<string> candidates;
3025 vector<string> unused;
3026 set<string> all_sources;
3035 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3037 /* this is mostly for windows which doesn't allow file
3038 * renaming if the file is in use. But we don't special
3039 * case it because we need to know if this causes
3040 * problems, and the easiest way to notice that is to
3041 * keep it in place for all platforms.
3044 request_stop (false);
3046 _butler->wait_until_finished ();
3048 /* consider deleting all unused playlists */
3050 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3055 /* sync the "all regions" property of each playlist with its current state
3058 playlists->sync_all_regions_with_regions ();
3060 /* find all un-used sources */
3065 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3067 SourceMap::iterator tmp;
3072 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3076 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3077 dead_sources.push_back (i->second);
3078 i->second->drop_references ();
3084 /* build a list of all the possible audio directories for the session */
3086 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3087 SessionDirectory sdir ((*i).path);
3088 asp += sdir.sound_path();
3090 audio_path += asp.to_string();
3093 /* build a list of all the possible midi directories for the session */
3095 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3096 SessionDirectory sdir ((*i).path);
3097 msp += sdir.midi_path();
3099 midi_path += msp.to_string();
3101 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3102 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3104 /* find all sources, but don't use this snapshot because the
3105 state file on disk still references sources we may have already
3109 find_all_sources_across_snapshots (all_sources, true);
3111 /* add our current source list
3114 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3115 boost::shared_ptr<FileSource> fs;
3116 SourceMap::iterator tmp = i;
3119 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3121 /* this is mostly for windows which doesn't allow file
3122 * renaming if the file is in use. But we don't special
3123 * case it because we need to know if this causes
3124 * problems, and the easiest way to notice that is to
3125 * keep it in place for all platforms.
3130 if (!fs->is_stub()) {
3132 if (playlists->source_use_count (fs) != 0) {
3133 all_sources.insert (fs->path());
3136 /* we might not remove this source from disk, because it may be used
3137 by other snapshots, but its not being used in this version
3138 so lets get rid of it now, along with any representative regions
3142 RegionFactory::remove_regions_using_source (i->second);
3144 // also remove source from all_sources
3146 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3147 spath = Glib::path_get_basename (*j);
3148 if (spath == i->second->name()) {
3149 all_sources.erase (j);
3162 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3167 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3169 tmppath1 = canonical_path (spath);
3170 tmppath2 = canonical_path ((*i));
3172 if (tmppath1 == tmppath2) {
3179 unused.push_back (spath);
3183 /* now try to move all unused files into the "dead" directory(ies) */
3185 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3190 /* don't move the file across filesystems, just
3191 stick it in the `dead_dir_name' directory
3192 on whichever filesystem it was already on.
3195 if ((*x).find ("/sounds/") != string::npos) {
3197 /* old school, go up 1 level */
3199 newpath = Glib::path_get_dirname (*x); // "sounds"
3200 newpath = Glib::path_get_dirname (newpath); // "session-name"
3204 /* new school, go up 4 levels */
3206 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3207 newpath = Glib::path_get_dirname (newpath); // "session-name"
3208 newpath = Glib::path_get_dirname (newpath); // "interchange"
3209 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3212 newpath = Glib::build_filename (newpath, dead_dir_name);
3214 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3215 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3219 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3221 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3223 /* the new path already exists, try versioning */
3225 char buf[PATH_MAX+1];
3229 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3232 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3233 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3237 if (version == 999) {
3238 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3242 newpath = newpath_v;
3247 /* it doesn't exist, or we can't read it or something */
3251 g_stat ((*x).c_str(), &statbuf);
3253 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3254 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3255 (*x), newpath, strerror (errno))
3260 /* see if there an easy to find peakfile for this file, and remove it.
3263 string base = Glib::path_get_basename (*x);
3264 base += "%A"; /* this is what we add for the channel suffix of all native files,
3265 or for the first channel of embedded files. it will miss
3266 some peakfiles for other channels
3268 string peakpath = construct_peak_filepath (base);
3270 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3271 if (::g_unlink (peakpath.c_str()) != 0) {
3272 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3273 peakpath, _path, strerror (errno))
3275 /* try to back out */
3276 ::rename (newpath.c_str(), _path.c_str());
3281 rep.paths.push_back (*x);
3282 rep.space += statbuf.st_size;
3285 /* dump the history list */
3289 /* save state so we don't end up a session file
3290 referring to non-existent sources.
3297 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3303 Session::cleanup_trash_sources (CleanupReport& rep)
3305 // FIXME: needs adaptation for MIDI
3307 vector<space_and_path>::iterator i;
3313 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3315 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3317 clear_directory (dead_dir, &rep.space, &rep.paths);
3324 Session::set_dirty ()
3326 /* never mark session dirty during loading */
3328 if (_state_of_the_state & Loading) {
3332 bool was_dirty = dirty();
3334 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3338 DirtyChanged(); /* EMIT SIGNAL */
3344 Session::set_clean ()
3346 bool was_dirty = dirty();
3348 _state_of_the_state = Clean;
3352 DirtyChanged(); /* EMIT SIGNAL */
3357 Session::set_deletion_in_progress ()
3359 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3363 Session::clear_deletion_in_progress ()
3365 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3369 Session::add_controllable (boost::shared_ptr<Controllable> c)
3371 /* this adds a controllable to the list managed by the Session.
3372 this is a subset of those managed by the Controllable class
3373 itself, and represents the only ones whose state will be saved
3374 as part of the session.
3377 Glib::Threads::Mutex::Lock lm (controllables_lock);
3378 controllables.insert (c);
3381 struct null_deleter { void operator()(void const *) const {} };
3384 Session::remove_controllable (Controllable* c)
3386 if (_state_of_the_state & Deletion) {
3390 Glib::Threads::Mutex::Lock lm (controllables_lock);
3392 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3394 if (x != controllables.end()) {
3395 controllables.erase (x);
3399 boost::shared_ptr<Controllable>
3400 Session::controllable_by_id (const PBD::ID& id)
3402 Glib::Threads::Mutex::Lock lm (controllables_lock);
3404 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3405 if ((*i)->id() == id) {
3410 return boost::shared_ptr<Controllable>();
3413 boost::shared_ptr<Controllable>
3414 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3416 boost::shared_ptr<Controllable> c;
3417 boost::shared_ptr<Stripable> s;
3418 boost::shared_ptr<Route> r;
3420 switch (desc.top_level_type()) {
3421 case ControllableDescriptor::NamedRoute:
3423 std::string str = desc.top_level_name();
3424 if (str == "Master" || str == "master") {
3426 } else if (str == "control" || str == "listen") {
3429 s = route_by_name (desc.top_level_name());
3434 case ControllableDescriptor::PresentationOrderRoute:
3435 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3438 case ControllableDescriptor::PresentationOrderVCA:
3439 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3442 case ControllableDescriptor::SelectionCount:
3443 s = route_by_selected_count (desc.selection_id());
3451 r = boost::dynamic_pointer_cast<Route> (s);
3453 switch (desc.subtype()) {
3454 case ControllableDescriptor::Gain:
3455 c = s->gain_control ();
3458 case ControllableDescriptor::Trim:
3459 c = s->trim_control ();
3462 case ControllableDescriptor::Solo:
3463 c = s->solo_control();
3466 case ControllableDescriptor::Mute:
3467 c = s->mute_control();
3470 case ControllableDescriptor::Recenable:
3471 c = s->recenable_control ();
3474 case ControllableDescriptor::PanDirection:
3475 c = s->pan_azimuth_control();
3478 case ControllableDescriptor::PanWidth:
3479 c = s->pan_width_control();
3482 case ControllableDescriptor::PanElevation:
3483 c = s->pan_elevation_control();
3486 case ControllableDescriptor::Balance:
3487 /* XXX simple pan control */
3490 case ControllableDescriptor::PluginParameter:
3492 uint32_t plugin = desc.target (0);
3493 uint32_t parameter_index = desc.target (1);
3495 /* revert to zero based counting */
3501 if (parameter_index > 0) {
3509 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3512 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3513 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3518 case ControllableDescriptor::SendGain: {
3519 uint32_t send = desc.target (0);
3526 c = r->send_level_controllable (send);
3531 /* relax and return a null pointer */
3539 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3542 Stateful::add_instant_xml (node, _path);
3545 if (write_to_config) {
3546 Config->add_instant_xml (node);
3551 Session::instant_xml (const string& node_name)
3553 return Stateful::instant_xml (node_name, _path);
3557 Session::save_history (string snapshot_name)
3565 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3566 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3570 if (snapshot_name.empty()) {
3571 snapshot_name = _current_snapshot_name;
3574 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3575 const string backup_filename = history_filename + backup_suffix;
3576 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3577 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3579 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3580 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3581 error << _("could not backup old history file, current history not saved") << endmsg;
3586 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3588 if (!tree.write (xml_path))
3590 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3592 if (g_remove (xml_path.c_str()) != 0) {
3593 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3594 xml_path, g_strerror (errno)) << endmsg;
3596 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3597 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3598 backup_path, g_strerror (errno)) << endmsg;
3608 Session::restore_history (string snapshot_name)
3612 if (snapshot_name.empty()) {
3613 snapshot_name = _current_snapshot_name;
3616 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3617 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3619 info << "Loading history from " << xml_path << endmsg;
3621 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3622 info << string_compose (_("%1: no history file \"%2\" for this session."),
3623 _name, xml_path) << endmsg;
3627 if (!tree.read (xml_path)) {
3628 error << string_compose (_("Could not understand session history file \"%1\""),
3629 xml_path) << endmsg;
3636 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3639 UndoTransaction* ut = new UndoTransaction ();
3642 ut->set_name(t->property("name")->value());
3643 stringstream ss(t->property("tv-sec")->value());
3645 ss.str(t->property("tv-usec")->value());
3647 ut->set_timestamp(tv);
3649 for (XMLNodeConstIterator child_it = t->children().begin();
3650 child_it != t->children().end(); child_it++)
3652 XMLNode *n = *child_it;
3655 if (n->name() == "MementoCommand" ||
3656 n->name() == "MementoUndoCommand" ||
3657 n->name() == "MementoRedoCommand") {
3659 if ((c = memento_command_factory(n))) {
3663 } else if (n->name() == "NoteDiffCommand") {
3664 PBD::ID id (n->property("midi-source")->value());
3665 boost::shared_ptr<MidiSource> midi_source =
3666 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3668 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3670 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3673 } else if (n->name() == "SysExDiffCommand") {
3675 PBD::ID id (n->property("midi-source")->value());
3676 boost::shared_ptr<MidiSource> midi_source =
3677 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3679 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3681 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3684 } else if (n->name() == "PatchChangeDiffCommand") {
3686 PBD::ID id (n->property("midi-source")->value());
3687 boost::shared_ptr<MidiSource> midi_source =
3688 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3690 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3692 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3695 } else if (n->name() == "StatefulDiffCommand") {
3696 if ((c = stateful_diff_command_factory (n))) {
3697 ut->add_command (c);
3700 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3711 Session::config_changed (std::string p, bool ours)
3717 if (p == "seamless-loop") {
3719 } else if (p == "rf-speed") {
3721 } else if (p == "auto-loop") {
3723 } else if (p == "auto-input") {
3725 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3726 /* auto-input only makes a difference if we're rolling */
3727 set_track_monitor_input_status (!config.get_auto_input());
3730 } else if (p == "punch-in") {
3734 if ((location = _locations->auto_punch_location()) != 0) {
3736 if (config.get_punch_in ()) {
3737 replace_event (SessionEvent::PunchIn, location->start());
3739 remove_event (location->start(), SessionEvent::PunchIn);
3743 } else if (p == "punch-out") {
3747 if ((location = _locations->auto_punch_location()) != 0) {
3749 if (config.get_punch_out()) {
3750 replace_event (SessionEvent::PunchOut, location->end());
3752 clear_events (SessionEvent::PunchOut);
3756 } else if (p == "edit-mode") {
3758 Glib::Threads::Mutex::Lock lm (playlists->lock);
3760 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3761 (*i)->set_edit_mode (Config->get_edit_mode ());
3764 } else if (p == "use-video-sync") {
3766 waiting_for_sync_offset = config.get_use_video_sync();
3768 } else if (p == "mmc-control") {
3770 //poke_midi_thread ();
3772 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3774 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3776 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3778 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3780 } else if (p == "midi-control") {
3782 //poke_midi_thread ();
3784 } else if (p == "raid-path") {
3786 setup_raid_path (config.get_raid_path());
3788 } else if (p == "timecode-format") {
3792 } else if (p == "video-pullup") {
3796 } else if (p == "seamless-loop") {
3798 if (play_loop && transport_rolling()) {
3799 // to reset diskstreams etc
3800 request_play_loop (true);
3803 } else if (p == "rf-speed") {
3805 cumulative_rf_motion = 0;
3808 } else if (p == "click-sound") {
3810 setup_click_sounds (1);
3812 } else if (p == "click-emphasis-sound") {
3814 setup_click_sounds (-1);
3816 } else if (p == "clicking") {
3818 if (Config->get_clicking()) {
3819 if (_click_io && click_data) { // don't require emphasis data
3826 } else if (p == "click-gain") {
3829 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3832 } else if (p == "send-mtc") {
3834 if (Config->get_send_mtc ()) {
3835 /* mark us ready to send */
3836 next_quarter_frame_to_send = 0;
3839 } else if (p == "send-mmc") {
3841 _mmc->enable_send (Config->get_send_mmc ());
3843 } else if (p == "midi-feedback") {
3845 session_midi_feedback = Config->get_midi_feedback();
3847 } else if (p == "jack-time-master") {
3849 engine().reset_timebase ();
3851 } else if (p == "native-file-header-format") {
3853 if (!first_file_header_format_reset) {
3854 reset_native_file_format ();
3857 first_file_header_format_reset = false;
3859 } else if (p == "native-file-data-format") {
3861 if (!first_file_data_format_reset) {
3862 reset_native_file_format ();
3865 first_file_data_format_reset = false;
3867 } else if (p == "external-sync") {
3868 if (!config.get_external_sync()) {
3869 drop_sync_source ();
3871 switch_to_sync_source (Config->get_sync_source());
3873 } else if (p == "denormal-model") {
3875 } else if (p == "history-depth") {
3876 set_history_depth (Config->get_history_depth());
3877 } else if (p == "remote-model") {
3878 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3881 } else if (p == "initial-program-change") {
3883 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3886 buf[0] = MIDI::program; // channel zero by default
3887 buf[1] = (Config->get_initial_program_change() & 0x7f);
3889 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3891 } else if (p == "solo-mute-override") {
3892 // catch_up_on_solo_mute_override ();
3893 } else if (p == "listen-position" || p == "pfl-position") {
3894 listen_position_changed ();
3895 } else if (p == "solo-control-is-listen-control") {
3896 solo_control_mode_changed ();
3897 } else if (p == "solo-mute-gain") {
3898 _solo_cut_control->Changed (true, Controllable::NoGroup);
3899 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3900 last_timecode_valid = false;
3901 } else if (p == "playback-buffer-seconds") {
3902 AudioSource::allocate_working_buffers (frame_rate());
3903 } else if (p == "ltc-source-port") {
3904 reconnect_ltc_input ();
3905 } else if (p == "ltc-sink-port") {
3906 reconnect_ltc_output ();
3907 } else if (p == "timecode-generator-offset") {
3908 ltc_tx_parse_offset();
3909 } else if (p == "auto-return-target-list") {
3910 follow_playhead_priority ();
3917 Session::set_history_depth (uint32_t d)
3919 _history.set_depth (d);
3923 Session::load_diskstreams_2X (XMLNode const & node, int)
3926 XMLNodeConstIterator citer;
3928 clist = node.children();
3930 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3933 /* diskstreams added automatically by DiskstreamCreated handler */
3934 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3935 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3936 _diskstreams_2X.push_back (dsp);
3938 error << _("Session: unknown diskstream type in XML") << endmsg;
3942 catch (failed_constructor& err) {
3943 error << _("Session: could not load diskstream via XML state") << endmsg;
3951 /** Connect things to the MMC object */
3953 Session::setup_midi_machine_control ()
3955 _mmc = new MIDI::MachineControl;
3957 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
3958 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
3960 if (!async_out || !async_out) {
3964 /* XXXX argh, passing raw pointers back into libmidi++ */
3966 MIDI::Port* mmc_in = async_in.get();
3967 MIDI::Port* mmc_out = async_out.get();
3969 _mmc->set_ports (mmc_in, mmc_out);
3971 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3972 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3973 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3974 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3975 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3976 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3977 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3978 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3979 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3980 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3981 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3982 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3983 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3985 /* also handle MIDI SPP because its so common */
3987 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3988 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3989 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3992 boost::shared_ptr<Controllable>
3993 Session::solo_cut_control() const
3995 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3996 controls in Ardour that currently get presented to the user in the GUI that require
3997 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3999 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4000 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4004 return _solo_cut_control;
4008 Session::save_snapshot_name (const std::string & n)
4010 /* assure Stateful::_instant_xml is loaded
4011 * add_instant_xml() only adds to existing data and defaults
4012 * to use an empty Tree otherwise
4014 instant_xml ("LastUsedSnapshot");
4016 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4017 last_used_snapshot->add_property ("name", string(n));
4018 add_instant_xml (*last_used_snapshot, false);
4022 Session::set_snapshot_name (const std::string & n)
4024 _current_snapshot_name = n;
4025 save_snapshot_name (n);
4029 Session::rename (const std::string& new_name)
4031 string legal_name = legalize_for_path (new_name);
4037 string const old_sources_root = _session_dir->sources_root();
4039 if (!_writable || (_state_of_the_state & CannotSave)) {
4040 error << _("Cannot rename read-only session.") << endmsg;
4041 return 0; // don't show "messed up" warning
4043 if (record_status() == Recording) {
4044 error << _("Cannot rename session while recording") << endmsg;
4045 return 0; // don't show "messed up" warning
4048 StateProtector stp (this);
4053 * interchange subdirectory
4057 * Backup files are left unchanged and not renamed.
4060 /* Windows requires that we close all files before attempting the
4061 * rename. This works on other platforms, but isn't necessary there.
4062 * Leave it in place for all platforms though, since it may help
4063 * catch issues that could arise if the way Source files work ever
4064 * change (since most developers are not using Windows).
4067 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4068 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4074 /* pass one: not 100% safe check that the new directory names don't
4078 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4082 /* this is a stupid hack because Glib::path_get_dirname() is
4083 * lexical-only, and so passing it /a/b/c/ gives a different
4084 * result than passing it /a/b/c ...
4087 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4088 oldstr = oldstr.substr (0, oldstr.length() - 1);
4091 string base = Glib::path_get_dirname (oldstr);
4093 newstr = Glib::build_filename (base, legal_name);
4095 cerr << "Looking for " << newstr << endl;
4097 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4098 cerr << " exists\n";
4107 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4113 /* this is a stupid hack because Glib::path_get_dirname() is
4114 * lexical-only, and so passing it /a/b/c/ gives a different
4115 * result than passing it /a/b/c ...
4118 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4119 oldstr = oldstr.substr (0, oldstr.length() - 1);
4122 string base = Glib::path_get_dirname (oldstr);
4123 newstr = Glib::build_filename (base, legal_name);
4125 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4127 cerr << "Rename " << oldstr << " => " << newstr << endl;
4128 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4129 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4130 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4134 /* Reset path in "session dirs" */
4139 /* reset primary SessionDirectory object */
4142 (*_session_dir) = newstr;
4147 /* now rename directory below session_dir/interchange */
4149 string old_interchange_dir;
4150 string new_interchange_dir;
4152 /* use newstr here because we renamed the path
4153 * (folder/directory) that used to be oldstr to newstr above
4156 v.push_back (newstr);
4157 v.push_back (interchange_dir_name);
4158 v.push_back (Glib::path_get_basename (oldstr));
4160 old_interchange_dir = Glib::build_filename (v);
4163 v.push_back (newstr);
4164 v.push_back (interchange_dir_name);
4165 v.push_back (legal_name);
4167 new_interchange_dir = Glib::build_filename (v);
4169 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4171 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4172 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4173 old_interchange_dir, new_interchange_dir,
4176 error << string_compose (_("renaming %s as %2 failed (%3)"),
4177 old_interchange_dir, new_interchange_dir,
4186 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4187 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4189 cerr << "Rename " << oldstr << " => " << newstr << endl;
4191 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4192 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4193 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4199 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4201 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4202 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4204 cerr << "Rename " << oldstr << " => " << newstr << endl;
4206 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4207 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4208 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4213 /* remove old name from recent sessions */
4214 remove_recent_sessions (_path);
4217 /* update file source paths */
4219 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4220 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4222 string p = fs->path ();
4223 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4225 SourceFactory::setup_peakfile(i->second, true);
4229 set_snapshot_name (new_name);
4234 /* save state again to get everything just right */
4236 save_state (_current_snapshot_name);
4238 /* add to recent sessions */
4240 store_recent_sessions (new_name, _path);
4246 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4248 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4252 if (!tree.read (xmlpath)) {
4260 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4263 bool found_sr = false;
4264 bool found_data_format = false;
4266 if (get_session_info_from_path (tree, xmlpath)) {
4272 XMLProperty const * prop;
4273 XMLNode const * root (tree.root());
4275 if ((prop = root->property (X_("sample-rate"))) != 0) {
4276 sample_rate = atoi (prop->value());
4280 const XMLNodeList& children (root->children());
4281 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4282 const XMLNode* child = *c;
4283 if (child->name() == "Config") {
4284 const XMLNodeList& options (child->children());
4285 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4286 XMLNode const * option = *oc;
4287 XMLProperty const * name = option->property("name");
4293 if (name->value() == "native-file-data-format") {
4294 XMLProperty const * value = option->property ("value");
4296 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4298 found_data_format = true;
4304 if (found_data_format) {
4309 return !(found_sr && found_data_format); // zero if they are both found
4313 Session::get_snapshot_from_instant (const std::string& session_dir)
4315 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4317 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4322 if (!tree.read (instant_xml_path)) {
4326 XMLProperty const * prop;
4327 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4328 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4329 return prop->value();
4335 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4336 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4339 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4343 SourcePathMap source_path_map;
4345 boost::shared_ptr<AudioFileSource> afs;
4350 Glib::Threads::Mutex::Lock lm (source_lock);
4352 cerr << " total sources = " << sources.size();
4354 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4355 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4361 if (fs->within_session()) {
4365 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4366 source_path_map[fs->path()].push_back (fs);
4368 SeveralFileSources v;
4370 source_path_map.insert (make_pair (fs->path(), v));
4376 cerr << " fsources = " << total << endl;
4378 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4380 /* tell caller where we are */
4382 string old_path = i->first;
4384 callback (n, total, old_path);
4386 cerr << old_path << endl;
4390 switch (i->second.front()->type()) {
4391 case DataType::AUDIO:
4392 new_path = new_audio_source_path_for_embedded (old_path);
4395 case DataType::MIDI:
4396 /* XXX not implemented yet */
4400 if (new_path.empty()) {
4404 cerr << "Move " << old_path << " => " << new_path << endl;
4406 if (!copy_file (old_path, new_path)) {
4407 cerr << "failed !\n";
4411 /* make sure we stop looking in the external
4412 dir/folder. Remember, this is an all-or-nothing
4413 operations, it doesn't merge just some files.
4415 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4417 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4418 (*f)->set_path (new_path);
4423 save_state ("", false, false);
4429 bool accept_all_files (string const &, void *)
4435 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4437 /* 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.
4442 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4444 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4446 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4448 v.push_back (new_session_folder); /* full path */
4449 v.push_back (interchange_dir_name);
4450 v.push_back (new_session_path); /* just one directory/folder */
4451 v.push_back (typedir);
4452 v.push_back (Glib::path_get_basename (old_path));
4454 return Glib::build_filename (v);
4458 Session::save_as (SaveAs& saveas)
4460 vector<string> files;
4461 string current_folder = Glib::path_get_dirname (_path);
4462 string new_folder = legalize_for_path (saveas.new_name);
4463 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4464 int64_t total_bytes = 0;
4468 int32_t internal_file_cnt = 0;
4470 vector<string> do_not_copy_extensions;
4471 do_not_copy_extensions.push_back (statefile_suffix);
4472 do_not_copy_extensions.push_back (pending_suffix);
4473 do_not_copy_extensions.push_back (backup_suffix);
4474 do_not_copy_extensions.push_back (temp_suffix);
4475 do_not_copy_extensions.push_back (history_suffix);
4477 /* get total size */
4479 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4481 /* need to clear this because
4482 * find_files_matching_filter() is cumulative
4487 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4489 all += files.size();
4491 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4493 g_stat ((*i).c_str(), &gsb);
4494 total_bytes += gsb.st_size;
4498 /* save old values so we can switch back if we are not switching to the new session */
4500 string old_path = _path;
4501 string old_name = _name;
4502 string old_snapshot = _current_snapshot_name;
4503 string old_sd = _session_dir->root_path();
4504 vector<string> old_search_path[DataType::num_types];
4505 string old_config_search_path[DataType::num_types];
4507 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4508 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4509 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4510 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4512 /* switch session directory */
4514 (*_session_dir) = to_dir;
4516 /* create new tree */
4518 if (!_session_dir->create()) {
4519 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4524 /* copy all relevant files. Find each location in session_dirs,
4525 * and copy files from there to target.
4528 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4530 /* need to clear this because
4531 * find_files_matching_filter() is cumulative
4536 const size_t prefix_len = (*sd).path.size();
4538 /* Work just on the files within this session dir */
4540 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4542 /* add dir separator to protect against collisions with
4543 * track names (e.g. track named "audiofiles" or
4547 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4548 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4549 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4551 /* copy all the files. Handling is different for media files
4552 than others because of the *silly* subtree we have below the interchange
4553 folder. That really was a bad idea, but I'm not fixing it as part of
4554 implementing ::save_as().
4557 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4559 std::string from = *i;
4562 string filename = Glib::path_get_basename (from);
4563 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4564 if (filename == ".DS_STORE") {
4569 if (from.find (audiofile_dir_string) != string::npos) {
4571 /* audio file: only copy if asked */
4573 if (saveas.include_media && saveas.copy_media) {
4575 string to = make_new_media_path (*i, to_dir, new_folder);
4577 info << "media file copying from " << from << " to " << to << endmsg;
4579 if (!copy_file (from, to)) {
4580 throw Glib::FileError (Glib::FileError::IO_ERROR,
4581 string_compose(_("\ncopying \"%1\" failed !"), from));
4585 /* we found media files inside the session folder */
4587 internal_file_cnt++;
4589 } else if (from.find (midifile_dir_string) != string::npos) {
4591 /* midi file: always copy unless
4592 * creating an empty new session
4595 if (saveas.include_media) {
4597 string to = make_new_media_path (*i, to_dir, new_folder);
4599 info << "media file copying from " << from << " to " << to << endmsg;
4601 if (!copy_file (from, to)) {
4602 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4606 /* we found media files inside the session folder */
4608 internal_file_cnt++;
4610 } else if (from.find (analysis_dir_string) != string::npos) {
4612 /* make sure analysis dir exists in
4613 * new session folder, but we're not
4614 * copying analysis files here, see
4618 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4623 /* normal non-media file. Don't copy state, history, etc.
4626 bool do_copy = true;
4628 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4629 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4630 /* end of filename matches extension, do not copy file */
4636 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4637 /* don't copy peakfiles if
4638 * we're not copying media
4644 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4646 info << "attempting to make directory/folder " << to << endmsg;
4648 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4649 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4652 info << "attempting to copy " << from << " to " << to << endmsg;
4654 if (!copy_file (from, to)) {
4655 throw Glib::FileError (Glib::FileError::IO_ERROR,
4656 string_compose(_("\ncopying \"%1\" failed !"), from));
4661 /* measure file size even if we're not going to copy so that our Progress
4662 signals are correct, since we included these do-not-copy files
4663 in the computation of the total size and file count.
4667 g_stat (from.c_str(), &gsb);
4668 copied += gsb.st_size;
4671 double fraction = (double) copied / total_bytes;
4673 bool keep_going = true;
4675 if (saveas.copy_media) {
4677 /* no need or expectation of this if
4678 * media is not being copied, because
4679 * it will be fast(ish).
4682 /* tell someone "X percent, file M of N"; M is one-based */
4684 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4692 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4698 /* copy optional folders, if any */
4700 string old = plugins_dir ();
4701 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4702 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4703 copy_files (old, newdir);
4706 old = externals_dir ();
4707 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4708 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4709 copy_files (old, newdir);
4712 old = automation_dir ();
4713 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4714 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4715 copy_files (old, newdir);
4718 if (saveas.include_media) {
4720 if (saveas.copy_media) {
4721 #ifndef PLATFORM_WINDOWS
4722 /* There are problems with analysis files on
4723 * Windows, because they used a colon in their
4724 * names as late as 4.0. Colons are not legal
4725 * under Windows even if NTFS allows them.
4727 * This is a tricky problem to solve so for
4728 * just don't copy these files. They will be
4729 * regenerated as-needed anyway, subject to the
4730 * existing issue that the filenames will be
4731 * rejected by Windows, which is a separate
4732 * problem (though related).
4735 /* only needed if we are copying media, since the
4736 * analysis data refers to media data
4739 old = analysis_dir ();
4740 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4741 string newdir = Glib::build_filename (to_dir, "analysis");
4742 copy_files (old, newdir);
4744 #endif /* PLATFORM_WINDOWS */
4750 set_snapshot_name (saveas.new_name);
4751 _name = saveas.new_name;
4753 if (saveas.include_media && !saveas.copy_media) {
4755 /* reset search paths of the new session (which we're pretending to be right now) to
4756 include the original session search path, so we can still find all audio.
4759 if (internal_file_cnt) {
4760 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4761 ensure_search_path_includes (*s, DataType::AUDIO);
4762 cerr << "be sure to include " << *s << " for audio" << endl;
4765 /* we do not do this for MIDI because we copy
4766 all MIDI files if saveas.include_media is
4772 bool was_dirty = dirty ();
4774 save_state ("", false, false, !saveas.include_media);
4775 save_default_options ();
4777 if (saveas.copy_media && saveas.copy_external) {
4778 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4779 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4783 saveas.final_session_folder_name = _path;
4785 store_recent_sessions (_name, _path);
4787 if (!saveas.switch_to) {
4789 /* switch back to the way things were */
4793 set_snapshot_name (old_snapshot);
4795 (*_session_dir) = old_sd;
4801 if (internal_file_cnt) {
4802 /* reset these to their original values */
4803 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4804 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4809 /* prune session dirs, and update disk space statistics
4814 session_dirs.clear ();
4815 session_dirs.push_back (sp);
4816 refresh_disk_space ();
4818 /* ensure that all existing tracks reset their current capture source paths
4820 reset_write_sources (true, true);
4822 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4823 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4826 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4827 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4833 if (fs->within_session()) {
4834 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4835 fs->set_path (newpath);
4840 } catch (Glib::FileError& e) {
4842 saveas.failure_message = e.what();
4844 /* recursively remove all the directories */
4846 remove_directory (to_dir);
4854 saveas.failure_message = _("unknown reason");
4856 /* recursively remove all the directories */
4858 remove_directory (to_dir);