2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
95 #include "ardour/lv2_plugin.h"
96 #include "ardour/midi_model.h"
97 #include "ardour/midi_patch_manager.h"
98 #include "ardour/midi_region.h"
99 #include "ardour/midi_scene_changer.h"
100 #include "ardour/midi_source.h"
101 #include "ardour/midi_track.h"
102 #include "ardour/pannable.h"
103 #include "ardour/playlist_factory.h"
104 #include "ardour/playlist_source.h"
105 #include "ardour/port.h"
106 #include "ardour/processor.h"
107 #include "ardour/progress.h"
108 #include "ardour/profile.h"
109 #include "ardour/proxy_controllable.h"
110 #include "ardour/recent_sessions.h"
111 #include "ardour/region_factory.h"
112 #include "ardour/revision.h"
113 #include "ardour/route_group.h"
114 #include "ardour/send.h"
115 #include "ardour/session.h"
116 #include "ardour/session_directory.h"
117 #include "ardour/session_metadata.h"
118 #include "ardour/session_playlists.h"
119 #include "ardour/session_state_utils.h"
120 #include "ardour/silentfilesource.h"
121 #include "ardour/sndfilesource.h"
122 #include "ardour/source_factory.h"
123 #include "ardour/speakers.h"
124 #include "ardour/template_utils.h"
125 #include "ardour/tempo.h"
126 #include "ardour/ticker.h"
127 #include "ardour/user_bundle.h"
128 #include "ardour/vca.h"
129 #include "ardour/vca_manager.h"
131 #include "control_protocol/control_protocol.h"
133 #include "LuaBridge/LuaBridge.h"
135 #include "pbd/i18n.h"
139 using namespace ARDOUR;
142 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
145 Session::pre_engine_init (string fullpath)
147 if (fullpath.empty()) {
149 throw failed_constructor();
152 /* discover canonical fullpath */
154 _path = canonical_path(fullpath);
157 if (Profile->get_trx() ) {
158 // Waves TracksLive has a usecase of session replacement with a new one.
159 // We should check session state file (<session_name>.ardour) existance
160 // to determine if the session is new or not
162 string full_session_name = Glib::build_filename( fullpath, _name );
163 full_session_name += statefile_suffix;
165 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
167 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 /* finish initialization that can't be done in a normal C++ constructor
174 timerclear (&last_mmc_step);
175 g_atomic_int_set (&processing_prohibited, 0);
176 g_atomic_int_set (&_record_status, Disabled);
177 g_atomic_int_set (&_playback_load, 100);
178 g_atomic_int_set (&_capture_load, 100);
180 _all_route_group->set_active (true, this);
181 interpolation.add_channel_to (0, 0);
183 if (config.get_use_video_sync()) {
184 waiting_for_sync_offset = true;
186 waiting_for_sync_offset = false;
189 last_rr_session_dir = session_dirs.begin();
191 set_history_depth (Config->get_history_depth());
193 /* default: assume simple stereo speaker configuration */
195 _speakers->setup_default_speakers (2);
197 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
198 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
199 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
200 add_controllable (_solo_cut_control);
202 /* These are all static "per-class" signals */
204 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
205 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
206 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
207 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
208 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
210 /* stop IO objects from doing stuff until we're ready for them */
212 Delivery::disable_panners ();
213 IO::disable_connecting ();
217 Session::post_engine_init ()
219 BootMessage (_("Set block size and sample rate"));
221 set_block_size (_engine.samples_per_cycle());
222 set_frame_rate (_engine.sample_rate());
224 BootMessage (_("Using configuration"));
226 _midi_ports = new MidiPortManager;
228 MIDISceneChanger* msc;
230 _scene_changer = msc = new MIDISceneChanger (*this);
231 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
232 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
234 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
235 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
237 setup_midi_machine_control ();
239 if (_butler->start_thread()) {
243 if (start_midi_thread ()) {
247 setup_click_sounds (0);
248 setup_midi_control ();
250 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
251 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
254 /* tempo map requires sample rate knowledge */
257 _tempo_map = new TempoMap (_current_frame_rate);
258 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
259 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
261 /* MidiClock requires a tempo map */
264 midi_clock = new MidiClockTicker ();
265 midi_clock->set_session (this);
267 /* crossfades require sample rate knowledge */
269 SndFileSource::setup_standard_crossfades (*this, frame_rate());
270 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
272 AudioDiskstream::allocate_working_buffers();
273 refresh_disk_space ();
275 /* we're finally ready to call set_state() ... all objects have
276 * been created, the engine is running.
280 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
284 // set_state() will call setup_raid_path(), but if it's a new session we need
285 // to call setup_raid_path() here.
286 setup_raid_path (_path);
291 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
292 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
294 Config->map_parameters (ff);
295 config.map_parameters (ft);
296 _butler->map_parameters ();
298 /* Reset all panners */
300 Delivery::reset_panners ();
302 /* this will cause the CPM to instantiate any protocols that are in use
303 * (or mandatory), which will pass it this Session, and then call
304 * set_state() on each instantiated protocol to match stored state.
307 ControlProtocolManager::instance().set_session (this);
309 /* This must be done after the ControlProtocolManager set_session above,
310 as it will set states for ports which the ControlProtocolManager creates.
313 // XXX set state of MIDI::Port's
314 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
316 /* And this must be done after the MIDI::Manager::set_port_states as
317 * it will try to make connections whose details are loaded by set_port_states.
322 /* Let control protocols know that we are now all connected, so they
323 * could start talking to surfaces if they want to.
326 ControlProtocolManager::instance().midi_connectivity_established ();
328 if (_is_new && !no_auto_connect()) {
329 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
330 auto_connect_master_bus ();
333 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
335 /* update latencies */
337 initialize_latencies ();
339 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
340 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
341 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
343 } catch (AudioEngine::PortRegistrationFailure& err) {
344 /* handle this one in a different way than all others, so that its clear what happened */
345 error << err.what() << endmsg;
351 BootMessage (_("Reset Remote Controls"));
353 // send_full_time_code (0);
354 _engine.transport_locate (0);
356 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
357 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
359 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
362 /* initial program change will be delivered later; see ::config_changed() */
364 _state_of_the_state = Clean;
366 Port::set_connecting_blocked (false);
368 DirtyChanged (); /* EMIT SIGNAL */
372 } else if (state_was_pending) {
374 remove_pending_capture_state ();
375 state_was_pending = false;
378 /* Now, finally, we can fill the playback buffers */
380 BootMessage (_("Filling playback buffers"));
382 boost::shared_ptr<RouteList> rl = routes.reader();
383 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
384 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
385 if (trk && !trk->hidden()) {
386 trk->seek (_transport_frame, true);
394 Session::session_loaded ()
398 _state_of_the_state = Clean;
400 DirtyChanged (); /* EMIT SIGNAL */
404 } else if (state_was_pending) {
406 remove_pending_capture_state ();
407 state_was_pending = false;
410 /* Now, finally, we can fill the playback buffers */
412 BootMessage (_("Filling playback buffers"));
413 force_locate (_transport_frame, false);
417 Session::raid_path () const
419 Searchpath raid_search_path;
421 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
422 raid_search_path += (*i).path;
425 return raid_search_path.to_string ();
429 Session::setup_raid_path (string path)
438 session_dirs.clear ();
440 Searchpath search_path(path);
441 Searchpath sound_search_path;
442 Searchpath midi_search_path;
444 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
446 sp.blocks = 0; // not needed
447 session_dirs.push_back (sp);
449 SessionDirectory sdir(sp.path);
451 sound_search_path += sdir.sound_path ();
452 midi_search_path += sdir.midi_path ();
455 // reset the round-robin soundfile path thingie
456 last_rr_session_dir = session_dirs.begin();
460 Session::path_is_within_session (const std::string& path)
462 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
463 if (PBD::path_is_within (i->path, path)) {
471 Session::ensure_subdirs ()
475 dir = session_directory().peak_path();
477 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
478 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
482 dir = session_directory().sound_path();
484 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
489 dir = session_directory().midi_path();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = session_directory().dead_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().export_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = analysis_dir ();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = plugins_dir ();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = externals_dir ();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 /** @param session_template directory containing session template, or empty.
535 * Caller must not hold process lock.
538 Session::create (const string& session_template, BusProfile* bus_profile)
540 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
541 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
545 if (ensure_subdirs ()) {
549 _writable = exists_and_writable (_path);
551 if (!session_template.empty()) {
552 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
554 FILE* in = g_fopen (in_path.c_str(), "rb");
557 /* no need to call legalize_for_path() since the string
558 * in session_template is already a legal path name
560 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
562 FILE* out = g_fopen (out_path.c_str(), "wb");
566 stringstream new_session;
569 size_t charsRead = fread (buf, sizeof(char), 1024, in);
572 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
577 if (charsRead == 0) {
580 new_session.write (buf, charsRead);
584 string file_contents = new_session.str();
585 size_t writeSize = file_contents.length();
586 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
587 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
595 if (!ARDOUR::Profile->get_trx()) {
596 /* Copy plugin state files from template to new session */
597 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
598 copy_recurse (template_plugins, plugins_dir ());
604 error << string_compose (_("Could not open %1 for writing session template"), out_path)
611 error << string_compose (_("Could not open session template %1 for reading"), in_path)
618 if (Profile->get_trx()) {
620 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
621 Remember that this is a brand new session. Sessions
622 loaded from saved state will get this range from the saved state.
625 set_session_range_location (0, 0);
627 /* Initial loop location, from absolute zero, length 10 seconds */
629 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
630 _locations->add (loc, true);
631 set_auto_loop_location (loc);
634 _state_of_the_state = Clean;
636 /* set up Master Out and Monitor Out if necessary */
641 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
643 // Waves Tracks: always create master bus for Tracks
644 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
645 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
653 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
654 r->input()->ensure_io (count, false, this);
655 r->output()->ensure_io (count, false, this);
661 /* prohibit auto-connect to master, because there isn't one */
662 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
666 add_routes (rl, false, false, false, PresentationInfo::max_order);
669 // Waves Tracks: Skip this. Always use autoconnection for Tracks
670 if (!ARDOUR::Profile->get_trx()) {
672 /* this allows the user to override settings with an environment variable.
675 if (no_auto_connect()) {
676 bus_profile->input_ac = AutoConnectOption (0);
677 bus_profile->output_ac = AutoConnectOption (0);
680 Config->set_input_auto_connect (bus_profile->input_ac);
681 Config->set_output_auto_connect (bus_profile->output_ac);
685 if (Config->get_use_monitor_bus() && bus_profile) {
686 add_monitor_section ();
693 Session::maybe_write_autosave()
695 if (dirty() && record_status() != Recording) {
696 save_state("", true);
701 Session::remove_pending_capture_state ()
703 std::string pending_state_file_path(_session_dir->root_path());
705 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
707 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
709 if (g_remove (pending_state_file_path.c_str()) != 0) {
710 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
711 pending_state_file_path, g_strerror (errno)) << endmsg;
715 /** Rename a state file.
716 * @param old_name Old snapshot name.
717 * @param new_name New snapshot name.
720 Session::rename_state (string old_name, string new_name)
722 if (old_name == _current_snapshot_name || old_name == _name) {
723 /* refuse to rename the current snapshot or the "main" one */
727 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
728 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
730 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
731 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
733 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
734 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
735 old_name, new_name, g_strerror(errno)) << endmsg;
739 /** Remove a state file.
740 * @param snapshot_name Snapshot name.
743 Session::remove_state (string snapshot_name)
745 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
746 // refuse to remove the current snapshot or the "main" one
750 std::string xml_path(_session_dir->root_path());
752 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
754 if (!create_backup_file (xml_path)) {
755 // don't remove it if a backup can't be made
756 // create_backup_file will log the error.
761 if (g_remove (xml_path.c_str()) != 0) {
762 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
763 xml_path, g_strerror (errno)) << endmsg;
767 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
769 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
771 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
774 std::string xml_path(_session_dir->root_path());
776 /* prevent concurrent saves from different threads */
778 Glib::Threads::Mutex::Lock lm (save_state_lock);
780 if (!_writable || (_state_of_the_state & CannotSave)) {
784 if (g_atomic_int_get(&_suspend_save)) {
788 _save_queued = false;
790 if (!_engine.connected ()) {
791 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
798 const int64_t save_start_time = g_get_monotonic_time();
801 /* tell sources we're saving first, in case they write out to a new file
802 * which should be saved with the state rather than the old one */
803 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
805 i->second->session_saved();
806 } catch (Evoral::SMF::FileError& e) {
807 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
811 SessionSaveUnderway (); /* EMIT SIGNAL */
813 bool mark_as_clean = true;
815 if (!snapshot_name.empty() && !switch_to_snapshot) {
816 mark_as_clean = false;
820 mark_as_clean = false;
821 tree.set_root (&get_template());
823 tree.set_root (&get_state());
826 if (snapshot_name.empty()) {
827 snapshot_name = _current_snapshot_name;
828 } else if (switch_to_snapshot) {
829 set_snapshot_name (snapshot_name);
832 assert (!snapshot_name.empty());
836 /* proper save: use statefile_suffix (.ardour in English) */
838 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
840 /* make a backup copy of the old file */
842 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
843 // create_backup_file will log the error
849 /* pending save: use pending_suffix (.pending in English) */
850 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
853 std::string tmp_path(_session_dir->root_path());
854 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
856 cerr << "actually writing state to " << tmp_path << endl;
858 if (!tree.write (tmp_path)) {
859 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
860 if (g_remove (tmp_path.c_str()) != 0) {
861 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
862 tmp_path, g_strerror (errno)) << endmsg;
868 cerr << "renaming state to " << xml_path << endl;
870 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
871 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
872 tmp_path, xml_path, g_strerror(errno)) << endmsg;
873 if (g_remove (tmp_path.c_str()) != 0) {
874 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
875 tmp_path, g_strerror (errno)) << endmsg;
883 save_history (snapshot_name);
886 bool was_dirty = dirty();
888 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
891 DirtyChanged (); /* EMIT SIGNAL */
895 StateSaved (snapshot_name); /* EMIT SIGNAL */
899 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
900 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
906 Session::restore_state (string snapshot_name)
908 if (load_state (snapshot_name) == 0) {
909 set_state (*state_tree->root(), Stateful::loading_state_version);
916 Session::load_state (string snapshot_name)
921 state_was_pending = false;
923 /* check for leftover pending state from a crashed capture attempt */
925 std::string xmlpath(_session_dir->root_path());
926 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
928 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
930 /* there is pending state from a crashed capture attempt */
932 boost::optional<int> r = AskAboutPendingState();
933 if (r.get_value_or (1)) {
934 state_was_pending = true;
938 if (!state_was_pending) {
939 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
942 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
943 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
944 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
945 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
950 state_tree = new XMLTree;
954 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
956 if (!state_tree->read (xmlpath)) {
957 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
963 XMLNode const & root (*state_tree->root());
965 if (root.name() != X_("Session")) {
966 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
972 XMLProperty const * prop;
974 if ((prop = root.property ("version")) == 0) {
975 /* no version implies very old version of Ardour */
976 Stateful::loading_state_version = 1000;
978 if (prop->value().find ('.') != string::npos) {
979 /* old school version format */
980 if (prop->value()[0] == '2') {
981 Stateful::loading_state_version = 2000;
983 Stateful::loading_state_version = 3000;
986 Stateful::loading_state_version = atoi (prop->value());
990 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
992 std::string backup_path(_session_dir->root_path());
993 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
994 backup_path = Glib::build_filename (backup_path, backup_filename);
996 // only create a backup for a given statefile version once
998 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1000 VersionMismatch (xmlpath, backup_path);
1002 if (!copy_file (xmlpath, backup_path)) {;
1008 save_snapshot_name (snapshot_name);
1014 Session::load_options (const XMLNode& node)
1017 config.set_variables (node);
1022 Session::save_default_options ()
1024 return config.save_state();
1028 Session::get_state()
1034 Session::get_template()
1036 /* if we don't disable rec-enable, diskstreams
1037 will believe they need to store their capture
1038 sources in their state node.
1041 disable_record (false);
1043 return state(false);
1047 Session::state (bool full_state)
1050 XMLNode* node = new XMLNode("Session");
1054 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1055 node->add_property("version", buf);
1057 child = node->add_child ("ProgramVersion");
1058 child->add_property("created-with", created_with);
1060 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1061 child->add_property("modified-with", modified_with);
1063 /* store configuration settings */
1067 node->add_property ("name", _name);
1068 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1069 node->add_property ("sample-rate", buf);
1071 if (session_dirs.size() > 1) {
1075 vector<space_and_path>::iterator i = session_dirs.begin();
1076 vector<space_and_path>::iterator next;
1078 ++i; /* skip the first one */
1082 while (i != session_dirs.end()) {
1086 if (next != session_dirs.end()) {
1087 p += G_SEARCHPATH_SEPARATOR;
1096 child = node->add_child ("Path");
1097 child->add_content (p);
1101 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1103 /* save the ID counter */
1105 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1106 node->add_property ("id-counter", buf);
1108 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1109 node->add_property ("name-counter", buf);
1111 /* save the event ID counter */
1113 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1114 node->add_property ("event-counter", buf);
1116 /* save the VCA counter */
1118 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1119 node->add_property ("vca-counter", buf);
1121 /* various options */
1123 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1124 if (!midi_port_nodes.empty()) {
1125 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1126 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1127 midi_port_stuff->add_child_nocopy (**n);
1129 node->add_child_nocopy (*midi_port_stuff);
1132 node->add_child_nocopy (config.get_variables ());
1134 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1136 child = node->add_child ("Sources");
1139 Glib::Threads::Mutex::Lock sl (source_lock);
1141 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1143 /* Don't save information about non-file Sources, or
1144 * about non-destructive file sources that are empty
1145 * and unused by any regions.
1148 boost::shared_ptr<FileSource> fs;
1150 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1152 if (!fs->destructive()) {
1153 if (fs->empty() && !fs->used()) {
1158 child->add_child_nocopy (siter->second->get_state());
1163 child = node->add_child ("Regions");
1166 Glib::Threads::Mutex::Lock rl (region_lock);
1167 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1168 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1169 boost::shared_ptr<Region> r = i->second;
1170 /* only store regions not attached to playlists */
1171 if (r->playlist() == 0) {
1172 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1173 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1175 child->add_child_nocopy (r->get_state ());
1180 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1182 if (!cassocs.empty()) {
1183 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1185 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1187 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1188 i->first->id().print (buf, sizeof (buf));
1189 can->add_property (X_("copy"), buf);
1190 i->second->id().print (buf, sizeof (buf));
1191 can->add_property (X_("original"), buf);
1192 ca->add_child_nocopy (*can);
1202 node->add_child_nocopy (_locations->get_state());
1205 Locations loc (*this);
1206 // for a template, just create a new Locations, populate it
1207 // with the default start and end, and get the state for that.
1208 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1209 range->set (max_framepos, 0);
1211 XMLNode& locations_state = loc.get_state();
1213 if (ARDOUR::Profile->get_trx() && _locations) {
1214 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1215 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1216 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1217 locations_state.add_child_nocopy ((*i)->get_state ());
1221 node->add_child_nocopy (locations_state);
1224 child = node->add_child ("Bundles");
1226 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1227 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1228 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1230 child->add_child_nocopy (b->get_state());
1235 node->add_child_nocopy (_vca_manager->get_state());
1237 child = node->add_child ("Routes");
1239 boost::shared_ptr<RouteList> r = routes.reader ();
1241 RoutePublicOrderSorter cmp;
1242 RouteList public_order (*r);
1243 public_order.sort (cmp);
1245 /* the sort should have put the monitor out first */
1248 assert (_monitor_out == public_order.front());
1251 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1252 if (!(*i)->is_auditioner()) {
1254 child->add_child_nocopy ((*i)->get_state());
1256 child->add_child_nocopy ((*i)->get_template());
1262 playlists->add_state (node, full_state);
1264 child = node->add_child ("RouteGroups");
1265 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1266 child->add_child_nocopy ((*i)->get_state());
1270 XMLNode* gain_child = node->add_child ("Click");
1271 gain_child->add_child_nocopy (_click_io->state (full_state));
1272 gain_child->add_child_nocopy (_click_gain->state (full_state));
1276 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1277 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1281 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1282 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1285 node->add_child_nocopy (_speakers->get_state());
1286 node->add_child_nocopy (_tempo_map->get_state());
1287 node->add_child_nocopy (get_control_protocol_state());
1290 node->add_child_copy (*_extra_xml);
1294 Glib::Threads::Mutex::Lock lm (lua_lock);
1297 luabridge::LuaRef savedstate ((*_lua_save)());
1298 saved = savedstate.cast<std::string>();
1300 lua.collect_garbage ();
1303 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1304 std::string b64s (b64);
1307 XMLNode* script_node = new XMLNode (X_("Script"));
1308 script_node->add_property (X_("lua"), LUA_VERSION);
1309 script_node->add_content (b64s);
1310 node->add_child_nocopy (*script_node);
1317 Session::get_control_protocol_state ()
1319 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1320 return cpm.get_state();
1324 Session::set_state (const XMLNode& node, int version)
1329 XMLProperty const * prop;
1332 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1334 if (node.name() != X_("Session")) {
1335 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1339 if ((prop = node.property ("name")) != 0) {
1340 _name = prop->value ();
1343 if ((prop = node.property (X_("sample-rate"))) != 0) {
1345 _base_frame_rate = atoi (prop->value());
1346 _nominal_frame_rate = _base_frame_rate;
1348 assert (AudioEngine::instance()->running ());
1349 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1350 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1351 if (r.get_value_or (0)) {
1357 created_with = "unknown";
1358 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1359 if ((prop = child->property (X_("created-with"))) != 0) {
1360 created_with = prop->value ();
1364 setup_raid_path(_session_dir->root_path());
1366 if ((prop = node.property (X_("end-is-free"))) != 0) {
1367 _session_range_end_is_free = string_is_affirmative (prop->value());
1370 if ((prop = node.property (X_("id-counter"))) != 0) {
1372 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1373 ID::init_counter (x);
1375 /* old sessions used a timebased counter, so fake
1376 the startup ID counter based on a standard
1381 ID::init_counter (now);
1384 if ((prop = node.property (X_("name-counter"))) != 0) {
1385 init_name_id_counter (atoi (prop->value()));
1388 if ((prop = node.property (X_("event-counter"))) != 0) {
1389 Evoral::init_event_id_counter (atoi (prop->value()));
1392 if ((prop = node.property (X_("vca-counter"))) != 0) {
1394 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1395 VCA::set_next_vca_number (x);
1397 VCA::set_next_vca_number (1);
1400 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1401 _midi_ports->set_midi_port_states (child->children());
1404 IO::disable_connecting ();
1406 Stateful::save_extra_xml (node);
1408 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1409 load_options (*child);
1410 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1411 load_options (*child);
1413 error << _("Session: XML state has no options section") << endmsg;
1416 if (version >= 3000) {
1417 if ((child = find_named_node (node, "Metadata")) == 0) {
1418 warning << _("Session: XML state has no metadata section") << endmsg;
1419 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1424 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1425 _speakers->set_state (*child, version);
1428 if ((child = find_named_node (node, "Sources")) == 0) {
1429 error << _("Session: XML state has no sources section") << endmsg;
1431 } else if (load_sources (*child)) {
1435 if ((child = find_named_node (node, "TempoMap")) == 0) {
1436 error << _("Session: XML state has no Tempo Map section") << endmsg;
1438 } else if (_tempo_map->set_state (*child, version)) {
1442 if ((child = find_named_node (node, "Locations")) == 0) {
1443 error << _("Session: XML state has no locations section") << endmsg;
1445 } else if (_locations->set_state (*child, version)) {
1449 locations_changed ();
1451 if (_session_range_location) {
1452 AudioFileSource::set_header_position_offset (_session_range_location->start());
1455 if ((child = find_named_node (node, "Regions")) == 0) {
1456 error << _("Session: XML state has no Regions section") << endmsg;
1458 } else if (load_regions (*child)) {
1462 if ((child = find_named_node (node, "Playlists")) == 0) {
1463 error << _("Session: XML state has no playlists section") << endmsg;
1465 } else if (playlists->load (*this, *child)) {
1469 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1471 } else if (playlists->load_unused (*this, *child)) {
1475 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1476 if (load_compounds (*child)) {
1481 if (version >= 3000) {
1482 if ((child = find_named_node (node, "Bundles")) == 0) {
1483 warning << _("Session: XML state has no bundles section") << endmsg;
1486 /* We can't load Bundles yet as they need to be able
1487 to convert from port names to Port objects, which can't happen until
1489 _bundle_xml_node = new XMLNode (*child);
1493 if (version < 3000) {
1494 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1495 error << _("Session: XML state has no diskstreams section") << endmsg;
1497 } else if (load_diskstreams_2X (*child, version)) {
1502 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1503 _vca_manager->set_state (*child, version);
1506 if ((child = find_named_node (node, "Routes")) == 0) {
1507 error << _("Session: XML state has no routes section") << endmsg;
1509 } else if (load_routes (*child, version)) {
1513 /* Now that we have Routes and masters loaded, connect them if appropriate */
1515 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1517 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1518 _diskstreams_2X.clear ();
1520 if (version >= 3000) {
1522 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1523 error << _("Session: XML state has no route groups section") << endmsg;
1525 } else if (load_route_groups (*child, version)) {
1529 } else if (version < 3000) {
1531 if ((child = find_named_node (node, "EditGroups")) == 0) {
1532 error << _("Session: XML state has no edit groups section") << endmsg;
1534 } else if (load_route_groups (*child, version)) {
1538 if ((child = find_named_node (node, "MixGroups")) == 0) {
1539 error << _("Session: XML state has no mix groups section") << endmsg;
1541 } else if (load_route_groups (*child, version)) {
1546 if ((child = find_named_node (node, "Click")) == 0) {
1547 warning << _("Session: XML state has no click section") << endmsg;
1548 } else if (_click_io) {
1549 setup_click_state (&node);
1552 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1553 ControlProtocolManager::instance().set_state (*child, version);
1556 if ((child = find_named_node (node, "Script"))) {
1557 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1558 if (!(*n)->is_content ()) { continue; }
1560 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1562 Glib::Threads::Mutex::Lock lm (lua_lock);
1563 (*_lua_load)(std::string ((const char*)buf, size));
1564 } catch (luabridge::LuaException const& e) {
1565 cerr << "LuaException:" << e.what () << endl;
1571 update_route_record_state ();
1573 /* here beginneth the second phase ... */
1574 set_snapshot_name (_current_snapshot_name);
1576 StateReady (); /* EMIT SIGNAL */
1589 Session::load_routes (const XMLNode& node, int version)
1592 XMLNodeConstIterator niter;
1593 RouteList new_routes;
1595 nlist = node.children();
1599 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1601 boost::shared_ptr<Route> route;
1602 if (version < 3000) {
1603 route = XMLRouteFactory_2X (**niter, version);
1605 route = XMLRouteFactory (**niter, version);
1609 error << _("Session: cannot create Route from XML description.") << endmsg;
1613 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1615 new_routes.push_back (route);
1618 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1620 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1622 BootMessage (_("Finished adding tracks/busses"));
1627 boost::shared_ptr<Route>
1628 Session::XMLRouteFactory (const XMLNode& node, int version)
1630 boost::shared_ptr<Route> ret;
1632 if (node.name() != "Route") {
1636 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1638 DataType type = DataType::AUDIO;
1639 XMLProperty const * prop = node.property("default-type");
1642 type = DataType (prop->value());
1645 assert (type != DataType::NIL);
1649 boost::shared_ptr<Track> track;
1651 if (type == DataType::AUDIO) {
1652 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1654 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1657 if (track->init()) {
1661 if (track->set_state (node, version)) {
1665 BOOST_MARK_TRACK (track);
1669 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1670 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1672 if (r->init () == 0 && r->set_state (node, version) == 0) {
1673 BOOST_MARK_ROUTE (r);
1681 boost::shared_ptr<Route>
1682 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1684 boost::shared_ptr<Route> ret;
1686 if (node.name() != "Route") {
1690 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1692 ds_prop = node.property (X_("diskstream"));
1695 DataType type = DataType::AUDIO;
1696 XMLProperty const * prop = node.property("default-type");
1699 type = DataType (prop->value());
1702 assert (type != DataType::NIL);
1706 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1707 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1711 if (i == _diskstreams_2X.end()) {
1712 error << _("Could not find diskstream for route") << endmsg;
1713 return boost::shared_ptr<Route> ();
1716 boost::shared_ptr<Track> track;
1718 if (type == DataType::AUDIO) {
1719 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1721 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1724 if (track->init()) {
1728 if (track->set_state (node, version)) {
1732 track->set_diskstream (*i);
1734 BOOST_MARK_TRACK (track);
1738 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1739 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1741 if (r->init () == 0 && r->set_state (node, version) == 0) {
1742 BOOST_MARK_ROUTE (r);
1751 Session::load_regions (const XMLNode& node)
1754 XMLNodeConstIterator niter;
1755 boost::shared_ptr<Region> region;
1757 nlist = node.children();
1761 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1762 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1763 error << _("Session: cannot create Region from XML description.");
1764 XMLProperty const * name = (**niter).property("name");
1767 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1778 Session::load_compounds (const XMLNode& node)
1780 XMLNodeList calist = node.children();
1781 XMLNodeConstIterator caiter;
1782 XMLProperty const * caprop;
1784 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1785 XMLNode* ca = *caiter;
1789 if ((caprop = ca->property (X_("original"))) == 0) {
1792 orig_id = caprop->value();
1794 if ((caprop = ca->property (X_("copy"))) == 0) {
1797 copy_id = caprop->value();
1799 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1800 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1802 if (!orig || !copy) {
1803 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1809 RegionFactory::add_compound_association (orig, copy);
1816 Session::load_nested_sources (const XMLNode& node)
1819 XMLNodeConstIterator niter;
1821 nlist = node.children();
1823 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1824 if ((*niter)->name() == "Source") {
1826 /* it may already exist, so don't recreate it unnecessarily
1829 XMLProperty const * prop = (*niter)->property (X_("id"));
1831 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1835 ID source_id (prop->value());
1837 if (!source_by_id (source_id)) {
1840 SourceFactory::create (*this, **niter, true);
1842 catch (failed_constructor& err) {
1843 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1850 boost::shared_ptr<Region>
1851 Session::XMLRegionFactory (const XMLNode& node, bool full)
1853 XMLProperty const * type = node.property("type");
1857 const XMLNodeList& nlist = node.children();
1859 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1860 XMLNode *child = (*niter);
1861 if (child->name() == "NestedSource") {
1862 load_nested_sources (*child);
1866 if (!type || type->value() == "audio") {
1867 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1868 } else if (type->value() == "midi") {
1869 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1872 } catch (failed_constructor& err) {
1873 return boost::shared_ptr<Region> ();
1876 return boost::shared_ptr<Region> ();
1879 boost::shared_ptr<AudioRegion>
1880 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1882 XMLProperty const * prop;
1883 boost::shared_ptr<Source> source;
1884 boost::shared_ptr<AudioSource> as;
1886 SourceList master_sources;
1887 uint32_t nchans = 1;
1890 if (node.name() != X_("Region")) {
1891 return boost::shared_ptr<AudioRegion>();
1894 if ((prop = node.property (X_("channels"))) != 0) {
1895 nchans = atoi (prop->value().c_str());
1898 if ((prop = node.property ("name")) == 0) {
1899 cerr << "no name for this region\n";
1903 if ((prop = node.property (X_("source-0"))) == 0) {
1904 if ((prop = node.property ("source")) == 0) {
1905 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1906 return boost::shared_ptr<AudioRegion>();
1910 PBD::ID s_id (prop->value());
1912 if ((source = source_by_id (s_id)) == 0) {
1913 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1914 return boost::shared_ptr<AudioRegion>();
1917 as = boost::dynamic_pointer_cast<AudioSource>(source);
1919 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1920 return boost::shared_ptr<AudioRegion>();
1923 sources.push_back (as);
1925 /* pickup other channels */
1927 for (uint32_t n=1; n < nchans; ++n) {
1928 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1929 if ((prop = node.property (buf)) != 0) {
1931 PBD::ID id2 (prop->value());
1933 if ((source = source_by_id (id2)) == 0) {
1934 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1935 return boost::shared_ptr<AudioRegion>();
1938 as = boost::dynamic_pointer_cast<AudioSource>(source);
1940 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1941 return boost::shared_ptr<AudioRegion>();
1943 sources.push_back (as);
1947 for (uint32_t n = 0; n < nchans; ++n) {
1948 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1949 if ((prop = node.property (buf)) != 0) {
1951 PBD::ID id2 (prop->value());
1953 if ((source = source_by_id (id2)) == 0) {
1954 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1955 return boost::shared_ptr<AudioRegion>();
1958 as = boost::dynamic_pointer_cast<AudioSource>(source);
1960 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1961 return boost::shared_ptr<AudioRegion>();
1963 master_sources.push_back (as);
1968 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1970 /* a final detail: this is the one and only place that we know how long missing files are */
1972 if (region->whole_file()) {
1973 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1974 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1976 sfp->set_length (region->length());
1981 if (!master_sources.empty()) {
1982 if (master_sources.size() != nchans) {
1983 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1985 region->set_master_sources (master_sources);
1993 catch (failed_constructor& err) {
1994 return boost::shared_ptr<AudioRegion>();
1998 boost::shared_ptr<MidiRegion>
1999 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2001 XMLProperty const * prop;
2002 boost::shared_ptr<Source> source;
2003 boost::shared_ptr<MidiSource> ms;
2006 if (node.name() != X_("Region")) {
2007 return boost::shared_ptr<MidiRegion>();
2010 if ((prop = node.property ("name")) == 0) {
2011 cerr << "no name for this region\n";
2015 if ((prop = node.property (X_("source-0"))) == 0) {
2016 if ((prop = node.property ("source")) == 0) {
2017 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2018 return boost::shared_ptr<MidiRegion>();
2022 PBD::ID s_id (prop->value());
2024 if ((source = source_by_id (s_id)) == 0) {
2025 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2026 return boost::shared_ptr<MidiRegion>();
2029 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2031 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2032 return boost::shared_ptr<MidiRegion>();
2035 sources.push_back (ms);
2038 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2039 /* a final detail: this is the one and only place that we know how long missing files are */
2041 if (region->whole_file()) {
2042 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2043 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2045 sfp->set_length (region->length());
2053 catch (failed_constructor& err) {
2054 return boost::shared_ptr<MidiRegion>();
2059 Session::get_sources_as_xml ()
2062 XMLNode* node = new XMLNode (X_("Sources"));
2063 Glib::Threads::Mutex::Lock lm (source_lock);
2065 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2066 node->add_child_nocopy (i->second->get_state());
2073 Session::reset_write_sources (bool mark_write_complete, bool force)
2075 boost::shared_ptr<RouteList> rl = routes.reader();
2076 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2077 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2079 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2080 tr->reset_write_sources(mark_write_complete, force);
2081 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2087 Session::load_sources (const XMLNode& node)
2090 XMLNodeConstIterator niter;
2091 boost::shared_ptr<Source> source; /* don't need this but it stops some
2092 * versions of gcc complaining about
2093 * discarded return values.
2096 nlist = node.children();
2100 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2103 if ((source = XMLSourceFactory (**niter)) == 0) {
2104 error << _("Session: cannot create Source from XML description.") << endmsg;
2107 } catch (MissingSource& err) {
2111 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2112 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2113 PROGRAM_NAME) << endmsg;
2117 if (!no_questions_about_missing_files) {
2118 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2123 switch (user_choice) {
2125 /* user added a new search location, so try again */
2130 /* user asked to quit the entire session load
2135 no_questions_about_missing_files = true;
2139 no_questions_about_missing_files = true;
2146 case DataType::AUDIO:
2147 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2150 case DataType::MIDI:
2151 /* The MIDI file is actually missing so
2152 * just create a new one in the same
2153 * location. Do not announce its
2157 if (!Glib::path_is_absolute (err.path)) {
2158 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2160 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2165 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2166 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2167 /* reset ID to match the missing one */
2168 source->set_id (**niter);
2169 /* Now we can announce it */
2170 SourceFactory::SourceCreated (source);
2181 boost::shared_ptr<Source>
2182 Session::XMLSourceFactory (const XMLNode& node)
2184 if (node.name() != "Source") {
2185 return boost::shared_ptr<Source>();
2189 /* note: do peak building in another thread when loading session state */
2190 return SourceFactory::create (*this, node, true);
2193 catch (failed_constructor& err) {
2194 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2195 return boost::shared_ptr<Source>();
2200 Session::save_template (string template_name, bool replace_existing)
2202 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2206 bool absolute_path = Glib::path_is_absolute (template_name);
2208 /* directory to put the template in */
2209 std::string template_dir_path;
2211 if (!absolute_path) {
2212 std::string user_template_dir(user_template_directory());
2214 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2215 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2216 user_template_dir, g_strerror (errno)) << endmsg;
2220 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2222 template_dir_path = template_name;
2225 if (!ARDOUR::Profile->get_trx()) {
2226 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2227 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2228 template_dir_path) << endmsg;
2232 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2233 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2234 template_dir_path, g_strerror (errno)) << endmsg;
2240 std::string template_file_path;
2242 if (ARDOUR::Profile->get_trx()) {
2243 template_file_path = template_name;
2245 if (absolute_path) {
2246 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2248 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2252 SessionSaveUnderway (); /* EMIT SIGNAL */
2257 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2258 tree.set_root (&get_template());
2261 if (!tree.write (template_file_path)) {
2262 error << _("template not saved") << endmsg;
2266 store_recent_templates (template_file_path);
2272 Session::refresh_disk_space ()
2274 #if __APPLE__ || __FreeBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2276 Glib::Threads::Mutex::Lock lm (space_lock);
2278 /* get freespace on every FS that is part of the session path */
2280 _total_free_4k_blocks = 0;
2281 _total_free_4k_blocks_uncertain = false;
2283 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2285 struct statfs statfsbuf;
2286 statfs (i->path.c_str(), &statfsbuf);
2288 double const scale = statfsbuf.f_bsize / 4096.0;
2290 /* See if this filesystem is read-only */
2291 struct statvfs statvfsbuf;
2292 statvfs (i->path.c_str(), &statvfsbuf);
2294 /* f_bavail can be 0 if it is undefined for whatever
2295 filesystem we are looking at; Samba shares mounted
2296 via GVFS are an example of this.
2298 if (statfsbuf.f_bavail == 0) {
2299 /* block count unknown */
2301 i->blocks_unknown = true;
2302 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2303 /* read-only filesystem */
2305 i->blocks_unknown = false;
2307 /* read/write filesystem with known space */
2308 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2309 i->blocks_unknown = false;
2312 _total_free_4k_blocks += i->blocks;
2313 if (i->blocks_unknown) {
2314 _total_free_4k_blocks_uncertain = true;
2317 #elif defined PLATFORM_WINDOWS
2318 vector<string> scanned_volumes;
2319 vector<string>::iterator j;
2320 vector<space_and_path>::iterator i;
2321 DWORD nSectorsPerCluster, nBytesPerSector,
2322 nFreeClusters, nTotalClusters;
2326 _total_free_4k_blocks = 0;
2328 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2329 strncpy (disk_drive, (*i).path.c_str(), 3);
2333 volume_found = false;
2334 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2336 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2337 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2338 i->blocks = (uint32_t)(nFreeBytes / 4096);
2340 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2341 if (0 == j->compare(disk_drive)) {
2342 volume_found = true;
2347 if (!volume_found) {
2348 scanned_volumes.push_back(disk_drive);
2349 _total_free_4k_blocks += i->blocks;
2354 if (0 == _total_free_4k_blocks) {
2355 strncpy (disk_drive, path().c_str(), 3);
2358 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2360 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2361 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2362 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2369 Session::get_best_session_directory_for_new_audio ()
2371 vector<space_and_path>::iterator i;
2372 string result = _session_dir->root_path();
2374 /* handle common case without system calls */
2376 if (session_dirs.size() == 1) {
2380 /* OK, here's the algorithm we're following here:
2382 We want to select which directory to use for
2383 the next file source to be created. Ideally,
2384 we'd like to use a round-robin process so as to
2385 get maximum performance benefits from splitting
2386 the files across multiple disks.
2388 However, in situations without much diskspace, an
2389 RR approach may end up filling up a filesystem
2390 with new files while others still have space.
2391 Its therefore important to pay some attention to
2392 the freespace in the filesystem holding each
2393 directory as well. However, if we did that by
2394 itself, we'd keep creating new files in the file
2395 system with the most space until it was as full
2396 as all others, thus negating any performance
2397 benefits of this RAID-1 like approach.
2399 So, we use a user-configurable space threshold. If
2400 there are at least 2 filesystems with more than this
2401 much space available, we use RR selection between them.
2402 If not, then we pick the filesystem with the most space.
2404 This gets a good balance between the two
2408 refresh_disk_space ();
2410 int free_enough = 0;
2412 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2413 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2418 if (free_enough >= 2) {
2419 /* use RR selection process, ensuring that the one
2423 i = last_rr_session_dir;
2426 if (++i == session_dirs.end()) {
2427 i = session_dirs.begin();
2430 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2431 SessionDirectory sdir(i->path);
2432 if (sdir.create ()) {
2434 last_rr_session_dir = i;
2439 } while (i != last_rr_session_dir);
2443 /* pick FS with the most freespace (and that
2444 seems to actually work ...)
2447 vector<space_and_path> sorted;
2448 space_and_path_ascending_cmp cmp;
2450 sorted = session_dirs;
2451 sort (sorted.begin(), sorted.end(), cmp);
2453 for (i = sorted.begin(); i != sorted.end(); ++i) {
2454 SessionDirectory sdir(i->path);
2455 if (sdir.create ()) {
2457 last_rr_session_dir = i;
2467 Session::automation_dir () const
2469 return Glib::build_filename (_path, automation_dir_name);
2473 Session::analysis_dir () const
2475 return Glib::build_filename (_path, analysis_dir_name);
2479 Session::plugins_dir () const
2481 return Glib::build_filename (_path, plugins_dir_name);
2485 Session::externals_dir () const
2487 return Glib::build_filename (_path, externals_dir_name);
2491 Session::load_bundles (XMLNode const & node)
2493 XMLNodeList nlist = node.children();
2494 XMLNodeConstIterator niter;
2498 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2499 if ((*niter)->name() == "InputBundle") {
2500 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2501 } else if ((*niter)->name() == "OutputBundle") {
2502 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2504 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2513 Session::load_route_groups (const XMLNode& node, int version)
2515 XMLNodeList nlist = node.children();
2516 XMLNodeConstIterator niter;
2520 if (version >= 3000) {
2522 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2523 if ((*niter)->name() == "RouteGroup") {
2524 RouteGroup* rg = new RouteGroup (*this, "");
2525 add_route_group (rg);
2526 rg->set_state (**niter, version);
2530 } else if (version < 3000) {
2532 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2533 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2534 RouteGroup* rg = new RouteGroup (*this, "");
2535 add_route_group (rg);
2536 rg->set_state (**niter, version);
2545 state_file_filter (const string &str, void* /*arg*/)
2547 return (str.length() > strlen(statefile_suffix) &&
2548 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2552 remove_end(string state)
2554 string statename(state);
2556 string::size_type start,end;
2557 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2558 statename = statename.substr (start+1);
2561 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2562 end = statename.length();
2565 return string(statename.substr (0, end));
2569 Session::possible_states (string path)
2571 vector<string> states;
2572 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2574 transform(states.begin(), states.end(), states.begin(), remove_end);
2576 sort (states.begin(), states.end());
2582 Session::possible_states () const
2584 return possible_states(_path);
2588 Session::add_route_group (RouteGroup* g)
2590 _route_groups.push_back (g);
2591 route_group_added (g); /* EMIT SIGNAL */
2593 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2594 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2595 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2601 Session::remove_route_group (RouteGroup& rg)
2603 list<RouteGroup*>::iterator i;
2605 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2606 _route_groups.erase (i);
2609 route_group_removed (); /* EMIT SIGNAL */
2613 /** Set a new order for our route groups, without adding or removing any.
2614 * @param groups Route group list in the new order.
2617 Session::reorder_route_groups (list<RouteGroup*> groups)
2619 _route_groups = groups;
2621 route_groups_reordered (); /* EMIT SIGNAL */
2627 Session::route_group_by_name (string name)
2629 list<RouteGroup *>::iterator i;
2631 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2632 if ((*i)->name() == name) {
2640 Session::all_route_group() const
2642 return *_all_route_group;
2646 Session::add_commands (vector<Command*> const & cmds)
2648 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2654 Session::add_command (Command* const cmd)
2656 assert (_current_trans);
2657 DEBUG_UNDO_HISTORY (
2658 string_compose ("Current Undo Transaction %1, adding command: %2",
2659 _current_trans->name (),
2661 _current_trans->add_command (cmd);
2664 PBD::StatefulDiffCommand*
2665 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2667 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2673 Session::begin_reversible_command (const string& name)
2675 begin_reversible_command (g_quark_from_string (name.c_str ()));
2678 /** Begin a reversible command using a GQuark to identify it.
2679 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2680 * but there must be as many begin...()s as there are commit...()s.
2683 Session::begin_reversible_command (GQuark q)
2685 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2686 to hold all the commands that are committed. This keeps the order of
2687 commands correct in the history.
2690 if (_current_trans == 0) {
2691 DEBUG_UNDO_HISTORY (string_compose (
2692 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2694 /* start a new transaction */
2695 assert (_current_trans_quarks.empty ());
2696 _current_trans = new UndoTransaction();
2697 _current_trans->set_name (g_quark_to_string (q));
2699 DEBUG_UNDO_HISTORY (
2700 string_compose ("Begin Reversible Command, current transaction: %1",
2701 _current_trans->name ()));
2704 _current_trans_quarks.push_front (q);
2708 Session::abort_reversible_command ()
2710 if (_current_trans != 0) {
2711 DEBUG_UNDO_HISTORY (
2712 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2713 _current_trans->clear();
2714 delete _current_trans;
2716 _current_trans_quarks.clear();
2721 Session::commit_reversible_command (Command *cmd)
2723 assert (_current_trans);
2724 assert (!_current_trans_quarks.empty ());
2729 DEBUG_UNDO_HISTORY (
2730 string_compose ("Current Undo Transaction %1, adding command: %2",
2731 _current_trans->name (),
2733 _current_trans->add_command (cmd);
2736 DEBUG_UNDO_HISTORY (
2737 string_compose ("Commit Reversible Command, current transaction: %1",
2738 _current_trans->name ()));
2740 _current_trans_quarks.pop_front ();
2742 if (!_current_trans_quarks.empty ()) {
2743 DEBUG_UNDO_HISTORY (
2744 string_compose ("Commit Reversible Command, transaction is not "
2745 "top-level, current transaction: %1",
2746 _current_trans->name ()));
2747 /* the transaction we're committing is not the top-level one */
2751 if (_current_trans->empty()) {
2752 /* no commands were added to the transaction, so just get rid of it */
2753 DEBUG_UNDO_HISTORY (
2754 string_compose ("Commit Reversible Command, No commands were "
2755 "added to current transaction: %1",
2756 _current_trans->name ()));
2757 delete _current_trans;
2762 gettimeofday (&now, 0);
2763 _current_trans->set_timestamp (now);
2765 _history.add (_current_trans);
2770 accept_all_audio_files (const string& path, void* /*arg*/)
2772 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2776 if (!AudioFileSource::safe_audio_file_extension (path)) {
2784 accept_all_midi_files (const string& path, void* /*arg*/)
2786 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2790 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2791 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2792 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2796 accept_all_state_files (const string& path, void* /*arg*/)
2798 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2802 std::string const statefile_ext (statefile_suffix);
2803 if (path.length() >= statefile_ext.length()) {
2804 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2811 Session::find_all_sources (string path, set<string>& result)
2816 if (!tree.read (path)) {
2820 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2825 XMLNodeConstIterator niter;
2827 nlist = node->children();
2831 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2833 XMLProperty const * prop;
2835 if ((prop = (*niter)->property (X_("type"))) == 0) {
2839 DataType type (prop->value());
2841 if ((prop = (*niter)->property (X_("name"))) == 0) {
2845 if (Glib::path_is_absolute (prop->value())) {
2846 /* external file, ignore */
2854 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2855 result.insert (found_path);
2863 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2865 vector<string> state_files;
2867 string this_snapshot_path;
2873 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2874 ripped = ripped.substr (0, ripped.length() - 1);
2877 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2879 if (state_files.empty()) {
2884 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2885 this_snapshot_path += statefile_suffix;
2887 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2889 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2891 if (exclude_this_snapshot && *i == this_snapshot_path) {
2892 cerr << "\texcluded\n";
2897 if (find_all_sources (*i, result) < 0) {
2905 struct RegionCounter {
2906 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2907 AudioSourceList::iterator iter;
2908 boost::shared_ptr<Region> region;
2911 RegionCounter() : count (0) {}
2915 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2917 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2918 return r.get_value_or (1);
2922 Session::cleanup_regions ()
2924 bool removed = false;
2925 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2927 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2929 uint32_t used = playlists->region_use_count (i->second);
2931 if (used == 0 && !i->second->automatic ()) {
2932 boost::weak_ptr<Region> w = i->second;
2935 RegionFactory::map_remove (w);
2942 // re-check to remove parent references of compound regions
2943 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2944 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2948 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2949 if (0 == playlists->region_use_count (i->second)) {
2950 boost::weak_ptr<Region> w = i->second;
2952 RegionFactory::map_remove (w);
2959 /* dump the history list */
2966 Session::can_cleanup_peakfiles () const
2968 if (deletion_in_progress()) {
2971 if (!_writable || (_state_of_the_state & CannotSave)) {
2972 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2975 if (record_status() == Recording) {
2976 error << _("Cannot cleanup peak-files while recording") << endmsg;
2983 Session::cleanup_peakfiles ()
2985 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2990 assert (can_cleanup_peakfiles ());
2991 assert (!peaks_cleanup_in_progres());
2993 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2995 int timeout = 5000; // 5 seconds
2996 while (!SourceFactory::files_with_peaks.empty()) {
2997 Glib::usleep (1000);
2998 if (--timeout < 0) {
2999 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3000 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3005 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3006 boost::shared_ptr<AudioSource> as;
3007 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3008 as->close_peakfile();
3012 PBD::clear_directory (session_directory().peak_path());
3014 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3016 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3017 boost::shared_ptr<AudioSource> as;
3018 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3019 SourceFactory::setup_peakfile(as, true);
3026 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3028 pl->deep_sources (*all_sources);
3032 Session::cleanup_sources (CleanupReport& rep)
3034 // FIXME: needs adaptation to midi
3036 vector<boost::shared_ptr<Source> > dead_sources;
3039 vector<string> candidates;
3040 vector<string> unused;
3041 set<string> sources_used_by_all_snapshots;
3048 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3050 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3052 /* this is mostly for windows which doesn't allow file
3053 * renaming if the file is in use. But we don't special
3054 * case it because we need to know if this causes
3055 * problems, and the easiest way to notice that is to
3056 * keep it in place for all platforms.
3059 request_stop (false);
3061 _butler->wait_until_finished ();
3063 /* consider deleting all unused playlists */
3065 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3070 /* sync the "all regions" property of each playlist with its current state
3073 playlists->sync_all_regions_with_regions ();
3075 /* find all un-used sources */
3080 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3082 SourceMap::iterator tmp;
3087 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3091 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3092 dead_sources.push_back (i->second);
3093 i->second->drop_references ();
3099 /* build a list of all the possible audio directories for the session */
3101 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3102 SessionDirectory sdir ((*i).path);
3103 asp += sdir.sound_path();
3105 audio_path += asp.to_string();
3108 /* build a list of all the possible midi directories for the session */
3110 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3111 SessionDirectory sdir ((*i).path);
3112 msp += sdir.midi_path();
3114 midi_path += msp.to_string();
3116 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3117 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3119 /* add sources from all other snapshots as "used", but don't use this
3120 snapshot because the state file on disk still references sources we
3121 may have already dropped.
3124 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3126 /* Although the region factory has a list of all regions ever created
3127 * for this session, we're only interested in regions actually in
3128 * playlists right now. So merge all playlist regions lists together.
3130 * This will include the playlists used within compound regions.
3133 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3135 /* add our current source list
3138 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3139 boost::shared_ptr<FileSource> fs;
3140 SourceMap::iterator tmp = i;
3143 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3149 /* this is mostly for windows which doesn't allow file
3150 * renaming if the file is in use. But we do not special
3151 * case it because we need to know if this causes
3152 * problems, and the easiest way to notice that is to
3153 * keep it in place for all platforms.
3158 if (!fs->is_stub()) {
3160 /* Note that we're checking a list of all
3161 * sources across all snapshots with the list
3162 * of sources used by this snapshot.
3165 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3166 /* this source is in use by this snapshot */
3167 sources_used_by_all_snapshots.insert (fs->path());
3168 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3170 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3171 /* this source is NOT in use by this snapshot
3174 /* remove all related regions from RegionFactory master list
3177 RegionFactory::remove_regions_using_source (i->second);
3179 /* remove from our current source list
3180 * also. We may not remove it from
3181 * disk, because it may be used by
3182 * other snapshots, but it isn't used inside this
3183 * snapshot anymore, so we don't need a
3194 /* now check each candidate source to see if it exists in the list of
3195 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3198 cerr << "Candidates: " << candidates.size() << endl;
3199 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3201 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3206 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3208 tmppath1 = canonical_path (spath);
3209 tmppath2 = canonical_path ((*i));
3211 cerr << "\t => " << tmppath2 << endl;
3213 if (tmppath1 == tmppath2) {
3220 unused.push_back (spath);
3224 cerr << "Actually unused: " << unused.size() << endl;
3226 if (unused.empty()) {
3232 /* now try to move all unused files into the "dead" directory(ies) */
3234 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3239 /* don't move the file across filesystems, just
3240 stick it in the `dead_dir_name' directory
3241 on whichever filesystem it was already on.
3244 if ((*x).find ("/sounds/") != string::npos) {
3246 /* old school, go up 1 level */
3248 newpath = Glib::path_get_dirname (*x); // "sounds"
3249 newpath = Glib::path_get_dirname (newpath); // "session-name"
3253 /* new school, go up 4 levels */
3255 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3256 newpath = Glib::path_get_dirname (newpath); // "session-name"
3257 newpath = Glib::path_get_dirname (newpath); // "interchange"
3258 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3261 newpath = Glib::build_filename (newpath, dead_dir_name);
3263 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3264 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3268 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3270 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3272 /* the new path already exists, try versioning */
3274 char buf[PATH_MAX+1];
3278 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3281 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3282 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3286 if (version == 999) {
3287 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3291 newpath = newpath_v;
3296 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3297 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3298 newpath, g_strerror (errno)) << endmsg;
3302 /* see if there an easy to find peakfile for this file, and remove it.
3305 string base = Glib::path_get_basename (*x);
3306 base += "%A"; /* this is what we add for the channel suffix of all native files,
3307 or for the first channel of embedded files. it will miss
3308 some peakfiles for other channels
3310 string peakpath = construct_peak_filepath (base);
3312 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3313 if (::g_unlink (peakpath.c_str ()) != 0) {
3314 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3315 g_strerror (errno)) << endmsg;
3316 /* try to back out */
3317 ::g_rename (newpath.c_str (), _path.c_str ());
3322 rep.paths.push_back (*x);
3323 rep.space += statbuf.st_size;
3326 /* dump the history list */
3330 /* save state so we don't end up a session file
3331 referring to non-existent sources.
3338 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3344 Session::cleanup_trash_sources (CleanupReport& rep)
3346 // FIXME: needs adaptation for MIDI
3348 vector<space_and_path>::iterator i;
3354 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3356 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3358 clear_directory (dead_dir, &rep.space, &rep.paths);
3365 Session::set_dirty ()
3367 /* never mark session dirty during loading */
3369 if (_state_of_the_state & Loading) {
3373 bool was_dirty = dirty();
3375 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3379 DirtyChanged(); /* EMIT SIGNAL */
3385 Session::set_clean ()
3387 bool was_dirty = dirty();
3389 _state_of_the_state = Clean;
3393 DirtyChanged(); /* EMIT SIGNAL */
3398 Session::set_deletion_in_progress ()
3400 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3404 Session::clear_deletion_in_progress ()
3406 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3410 Session::add_controllable (boost::shared_ptr<Controllable> c)
3412 /* this adds a controllable to the list managed by the Session.
3413 this is a subset of those managed by the Controllable class
3414 itself, and represents the only ones whose state will be saved
3415 as part of the session.
3418 Glib::Threads::Mutex::Lock lm (controllables_lock);
3419 controllables.insert (c);
3422 struct null_deleter { void operator()(void const *) const {} };
3425 Session::remove_controllable (Controllable* c)
3427 if (_state_of_the_state & Deletion) {
3431 Glib::Threads::Mutex::Lock lm (controllables_lock);
3433 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3435 if (x != controllables.end()) {
3436 controllables.erase (x);
3440 boost::shared_ptr<Controllable>
3441 Session::controllable_by_id (const PBD::ID& id)
3443 Glib::Threads::Mutex::Lock lm (controllables_lock);
3445 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3446 if ((*i)->id() == id) {
3451 return boost::shared_ptr<Controllable>();
3454 boost::shared_ptr<Controllable>
3455 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3457 boost::shared_ptr<Controllable> c;
3458 boost::shared_ptr<Stripable> s;
3459 boost::shared_ptr<Route> r;
3461 switch (desc.top_level_type()) {
3462 case ControllableDescriptor::NamedRoute:
3464 std::string str = desc.top_level_name();
3466 if (str == "Master" || str == "master") {
3468 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3470 } else if (str == "auditioner") {
3473 s = route_by_name (desc.top_level_name());
3479 case ControllableDescriptor::PresentationOrderRoute:
3480 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3483 case ControllableDescriptor::PresentationOrderTrack:
3484 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3487 case ControllableDescriptor::PresentationOrderBus:
3488 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3491 case ControllableDescriptor::PresentationOrderVCA:
3492 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3495 case ControllableDescriptor::SelectionCount:
3496 s = route_by_selected_count (desc.selection_id());
3504 r = boost::dynamic_pointer_cast<Route> (s);
3506 switch (desc.subtype()) {
3507 case ControllableDescriptor::Gain:
3508 c = s->gain_control ();
3511 case ControllableDescriptor::Trim:
3512 c = s->trim_control ();
3515 case ControllableDescriptor::Solo:
3516 c = s->solo_control();
3519 case ControllableDescriptor::Mute:
3520 c = s->mute_control();
3523 case ControllableDescriptor::Recenable:
3524 c = s->rec_enable_control ();
3527 case ControllableDescriptor::PanDirection:
3528 c = s->pan_azimuth_control();
3531 case ControllableDescriptor::PanWidth:
3532 c = s->pan_width_control();
3535 case ControllableDescriptor::PanElevation:
3536 c = s->pan_elevation_control();
3539 case ControllableDescriptor::Balance:
3540 /* XXX simple pan control */
3543 case ControllableDescriptor::PluginParameter:
3545 uint32_t plugin = desc.target (0);
3546 uint32_t parameter_index = desc.target (1);
3548 /* revert to zero based counting */
3554 if (parameter_index > 0) {
3562 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3565 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3566 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3571 case ControllableDescriptor::SendGain: {
3572 uint32_t send = desc.target (0);
3579 c = r->send_level_controllable (send);
3584 /* relax and return a null pointer */
3592 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3595 Stateful::add_instant_xml (node, _path);
3598 if (write_to_config) {
3599 Config->add_instant_xml (node);
3604 Session::instant_xml (const string& node_name)
3606 return Stateful::instant_xml (node_name, _path);
3610 Session::save_history (string snapshot_name)
3618 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3619 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3623 if (snapshot_name.empty()) {
3624 snapshot_name = _current_snapshot_name;
3627 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3628 const string backup_filename = history_filename + backup_suffix;
3629 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3630 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3632 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3633 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3634 error << _("could not backup old history file, current history not saved") << endmsg;
3639 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3641 if (!tree.write (xml_path))
3643 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3645 if (g_remove (xml_path.c_str()) != 0) {
3646 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3647 xml_path, g_strerror (errno)) << endmsg;
3649 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3650 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3651 backup_path, g_strerror (errno)) << endmsg;
3661 Session::restore_history (string snapshot_name)
3665 if (snapshot_name.empty()) {
3666 snapshot_name = _current_snapshot_name;
3669 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3670 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3672 info << "Loading history from " << xml_path << endmsg;
3674 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3675 info << string_compose (_("%1: no history file \"%2\" for this session."),
3676 _name, xml_path) << endmsg;
3680 if (!tree.read (xml_path)) {
3681 error << string_compose (_("Could not understand session history file \"%1\""),
3682 xml_path) << endmsg;
3689 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3692 UndoTransaction* ut = new UndoTransaction ();
3695 ut->set_name(t->property("name")->value());
3696 stringstream ss(t->property("tv-sec")->value());
3698 ss.str(t->property("tv-usec")->value());
3700 ut->set_timestamp(tv);
3702 for (XMLNodeConstIterator child_it = t->children().begin();
3703 child_it != t->children().end(); child_it++)
3705 XMLNode *n = *child_it;
3708 if (n->name() == "MementoCommand" ||
3709 n->name() == "MementoUndoCommand" ||
3710 n->name() == "MementoRedoCommand") {
3712 if ((c = memento_command_factory(n))) {
3716 } else if (n->name() == "NoteDiffCommand") {
3717 PBD::ID id (n->property("midi-source")->value());
3718 boost::shared_ptr<MidiSource> midi_source =
3719 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3721 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3723 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3726 } else if (n->name() == "SysExDiffCommand") {
3728 PBD::ID id (n->property("midi-source")->value());
3729 boost::shared_ptr<MidiSource> midi_source =
3730 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3732 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3734 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3737 } else if (n->name() == "PatchChangeDiffCommand") {
3739 PBD::ID id (n->property("midi-source")->value());
3740 boost::shared_ptr<MidiSource> midi_source =
3741 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3743 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3745 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3748 } else if (n->name() == "StatefulDiffCommand") {
3749 if ((c = stateful_diff_command_factory (n))) {
3750 ut->add_command (c);
3753 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3764 Session::config_changed (std::string p, bool ours)
3770 if (p == "seamless-loop") {
3772 } else if (p == "rf-speed") {
3774 } else if (p == "auto-loop") {
3776 } else if (p == "auto-input") {
3778 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3779 /* auto-input only makes a difference if we're rolling */
3780 set_track_monitor_input_status (!config.get_auto_input());
3783 } else if (p == "punch-in") {
3787 if ((location = _locations->auto_punch_location()) != 0) {
3789 if (config.get_punch_in ()) {
3790 replace_event (SessionEvent::PunchIn, location->start());
3792 remove_event (location->start(), SessionEvent::PunchIn);
3796 } else if (p == "punch-out") {
3800 if ((location = _locations->auto_punch_location()) != 0) {
3802 if (config.get_punch_out()) {
3803 replace_event (SessionEvent::PunchOut, location->end());
3805 clear_events (SessionEvent::PunchOut);
3809 } else if (p == "edit-mode") {
3811 Glib::Threads::Mutex::Lock lm (playlists->lock);
3813 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3814 (*i)->set_edit_mode (Config->get_edit_mode ());
3817 } else if (p == "use-video-sync") {
3819 waiting_for_sync_offset = config.get_use_video_sync();
3821 } else if (p == "mmc-control") {
3823 //poke_midi_thread ();
3825 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3827 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3829 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3831 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3833 } else if (p == "midi-control") {
3835 //poke_midi_thread ();
3837 } else if (p == "raid-path") {
3839 setup_raid_path (config.get_raid_path());
3841 } else if (p == "timecode-format") {
3845 } else if (p == "video-pullup") {
3849 } else if (p == "seamless-loop") {
3851 if (play_loop && transport_rolling()) {
3852 // to reset diskstreams etc
3853 request_play_loop (true);
3856 } else if (p == "rf-speed") {
3858 cumulative_rf_motion = 0;
3861 } else if (p == "click-sound") {
3863 setup_click_sounds (1);
3865 } else if (p == "click-emphasis-sound") {
3867 setup_click_sounds (-1);
3869 } else if (p == "clicking") {
3871 if (Config->get_clicking()) {
3872 if (_click_io && click_data) { // don't require emphasis data
3879 } else if (p == "click-gain") {
3882 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3885 } else if (p == "send-mtc") {
3887 if (Config->get_send_mtc ()) {
3888 /* mark us ready to send */
3889 next_quarter_frame_to_send = 0;
3892 } else if (p == "send-mmc") {
3894 _mmc->enable_send (Config->get_send_mmc ());
3896 } else if (p == "midi-feedback") {
3898 session_midi_feedback = Config->get_midi_feedback();
3900 } else if (p == "jack-time-master") {
3902 engine().reset_timebase ();
3904 } else if (p == "native-file-header-format") {
3906 if (!first_file_header_format_reset) {
3907 reset_native_file_format ();
3910 first_file_header_format_reset = false;
3912 } else if (p == "native-file-data-format") {
3914 if (!first_file_data_format_reset) {
3915 reset_native_file_format ();
3918 first_file_data_format_reset = false;
3920 } else if (p == "external-sync") {
3921 if (!config.get_external_sync()) {
3922 drop_sync_source ();
3924 switch_to_sync_source (Config->get_sync_source());
3926 } else if (p == "denormal-model") {
3928 } else if (p == "history-depth") {
3929 set_history_depth (Config->get_history_depth());
3930 } else if (p == "remote-model") {
3931 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3934 } else if (p == "initial-program-change") {
3936 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3939 buf[0] = MIDI::program; // channel zero by default
3940 buf[1] = (Config->get_initial_program_change() & 0x7f);
3942 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3944 } else if (p == "solo-mute-override") {
3945 // catch_up_on_solo_mute_override ();
3946 } else if (p == "listen-position" || p == "pfl-position") {
3947 listen_position_changed ();
3948 } else if (p == "solo-control-is-listen-control") {
3949 solo_control_mode_changed ();
3950 } else if (p == "solo-mute-gain") {
3951 _solo_cut_control->Changed (true, Controllable::NoGroup);
3952 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3953 last_timecode_valid = false;
3954 } else if (p == "playback-buffer-seconds") {
3955 AudioSource::allocate_working_buffers (frame_rate());
3956 } else if (p == "ltc-source-port") {
3957 reconnect_ltc_input ();
3958 } else if (p == "ltc-sink-port") {
3959 reconnect_ltc_output ();
3960 } else if (p == "timecode-generator-offset") {
3961 ltc_tx_parse_offset();
3962 } else if (p == "auto-return-target-list") {
3963 follow_playhead_priority ();
3970 Session::set_history_depth (uint32_t d)
3972 _history.set_depth (d);
3976 Session::load_diskstreams_2X (XMLNode const & node, int)
3979 XMLNodeConstIterator citer;
3981 clist = node.children();
3983 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3986 /* diskstreams added automatically by DiskstreamCreated handler */
3987 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3988 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3989 _diskstreams_2X.push_back (dsp);
3991 error << _("Session: unknown diskstream type in XML") << endmsg;
3995 catch (failed_constructor& err) {
3996 error << _("Session: could not load diskstream via XML state") << endmsg;
4004 /** Connect things to the MMC object */
4006 Session::setup_midi_machine_control ()
4008 _mmc = new MIDI::MachineControl;
4010 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4011 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4013 if (!async_out || !async_out) {
4017 /* XXXX argh, passing raw pointers back into libmidi++ */
4019 MIDI::Port* mmc_in = async_in.get();
4020 MIDI::Port* mmc_out = async_out.get();
4022 _mmc->set_ports (mmc_in, mmc_out);
4024 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4025 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4026 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4027 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4028 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4029 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4030 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4031 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4032 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4033 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4034 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4035 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4036 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4038 /* also handle MIDI SPP because its so common */
4040 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4041 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4042 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4045 boost::shared_ptr<Controllable>
4046 Session::solo_cut_control() const
4048 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4049 controls in Ardour that currently get presented to the user in the GUI that require
4050 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4052 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4053 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4057 return _solo_cut_control;
4061 Session::save_snapshot_name (const std::string & n)
4063 /* assure Stateful::_instant_xml is loaded
4064 * add_instant_xml() only adds to existing data and defaults
4065 * to use an empty Tree otherwise
4067 instant_xml ("LastUsedSnapshot");
4069 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4070 last_used_snapshot->add_property ("name", string(n));
4071 add_instant_xml (*last_used_snapshot, false);
4075 Session::set_snapshot_name (const std::string & n)
4077 _current_snapshot_name = n;
4078 save_snapshot_name (n);
4082 Session::rename (const std::string& new_name)
4084 string legal_name = legalize_for_path (new_name);
4090 string const old_sources_root = _session_dir->sources_root();
4092 if (!_writable || (_state_of_the_state & CannotSave)) {
4093 error << _("Cannot rename read-only session.") << endmsg;
4094 return 0; // don't show "messed up" warning
4096 if (record_status() == Recording) {
4097 error << _("Cannot rename session while recording") << endmsg;
4098 return 0; // don't show "messed up" warning
4101 StateProtector stp (this);
4106 * interchange subdirectory
4110 * Backup files are left unchanged and not renamed.
4113 /* Windows requires that we close all files before attempting the
4114 * rename. This works on other platforms, but isn't necessary there.
4115 * Leave it in place for all platforms though, since it may help
4116 * catch issues that could arise if the way Source files work ever
4117 * change (since most developers are not using Windows).
4120 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4121 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4127 /* pass one: not 100% safe check that the new directory names don't
4131 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4135 /* this is a stupid hack because Glib::path_get_dirname() is
4136 * lexical-only, and so passing it /a/b/c/ gives a different
4137 * result than passing it /a/b/c ...
4140 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4141 oldstr = oldstr.substr (0, oldstr.length() - 1);
4144 string base = Glib::path_get_dirname (oldstr);
4146 newstr = Glib::build_filename (base, legal_name);
4148 cerr << "Looking for " << newstr << endl;
4150 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4151 cerr << " exists\n";
4160 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4166 /* this is a stupid hack because Glib::path_get_dirname() is
4167 * lexical-only, and so passing it /a/b/c/ gives a different
4168 * result than passing it /a/b/c ...
4171 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4172 oldstr = oldstr.substr (0, oldstr.length() - 1);
4175 string base = Glib::path_get_dirname (oldstr);
4176 newstr = Glib::build_filename (base, legal_name);
4178 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4180 cerr << "Rename " << oldstr << " => " << newstr << endl;
4181 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4182 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4183 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4187 /* Reset path in "session dirs" */
4192 /* reset primary SessionDirectory object */
4195 (*_session_dir) = newstr;
4200 /* now rename directory below session_dir/interchange */
4202 string old_interchange_dir;
4203 string new_interchange_dir;
4205 /* use newstr here because we renamed the path
4206 * (folder/directory) that used to be oldstr to newstr above
4209 v.push_back (newstr);
4210 v.push_back (interchange_dir_name);
4211 v.push_back (Glib::path_get_basename (oldstr));
4213 old_interchange_dir = Glib::build_filename (v);
4216 v.push_back (newstr);
4217 v.push_back (interchange_dir_name);
4218 v.push_back (legal_name);
4220 new_interchange_dir = Glib::build_filename (v);
4222 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4224 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4225 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4226 old_interchange_dir, new_interchange_dir,
4229 error << string_compose (_("renaming %s as %2 failed (%3)"),
4230 old_interchange_dir, new_interchange_dir,
4239 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4240 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4242 cerr << "Rename " << oldstr << " => " << newstr << endl;
4244 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4245 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4246 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4252 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4254 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4255 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4257 cerr << "Rename " << oldstr << " => " << newstr << endl;
4259 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4260 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4261 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4266 /* remove old name from recent sessions */
4267 remove_recent_sessions (_path);
4270 /* update file source paths */
4272 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4273 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4275 string p = fs->path ();
4276 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4278 SourceFactory::setup_peakfile(i->second, true);
4282 set_snapshot_name (new_name);
4287 /* save state again to get everything just right */
4289 save_state (_current_snapshot_name);
4291 /* add to recent sessions */
4293 store_recent_sessions (new_name, _path);
4299 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4301 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4305 if (!tree.read (xmlpath)) {
4313 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4316 bool found_sr = false;
4317 bool found_data_format = false;
4319 if (get_session_info_from_path (tree, xmlpath)) {
4325 XMLProperty const * prop;
4326 XMLNode const * root (tree.root());
4328 if ((prop = root->property (X_("sample-rate"))) != 0) {
4329 sample_rate = atoi (prop->value());
4333 const XMLNodeList& children (root->children());
4334 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4335 const XMLNode* child = *c;
4336 if (child->name() == "Config") {
4337 const XMLNodeList& options (child->children());
4338 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4339 XMLNode const * option = *oc;
4340 XMLProperty const * name = option->property("name");
4346 if (name->value() == "native-file-data-format") {
4347 XMLProperty const * value = option->property ("value");
4349 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4351 found_data_format = true;
4357 if (found_data_format) {
4362 return !(found_sr && found_data_format); // zero if they are both found
4366 Session::get_snapshot_from_instant (const std::string& session_dir)
4368 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4370 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4375 if (!tree.read (instant_xml_path)) {
4379 XMLProperty const * prop;
4380 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4381 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4382 return prop->value();
4388 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4389 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4392 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4396 SourcePathMap source_path_map;
4398 boost::shared_ptr<AudioFileSource> afs;
4403 Glib::Threads::Mutex::Lock lm (source_lock);
4405 cerr << " total sources = " << sources.size();
4407 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4408 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4414 if (fs->within_session()) {
4418 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4419 source_path_map[fs->path()].push_back (fs);
4421 SeveralFileSources v;
4423 source_path_map.insert (make_pair (fs->path(), v));
4429 cerr << " fsources = " << total << endl;
4431 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4433 /* tell caller where we are */
4435 string old_path = i->first;
4437 callback (n, total, old_path);
4439 cerr << old_path << endl;
4443 switch (i->second.front()->type()) {
4444 case DataType::AUDIO:
4445 new_path = new_audio_source_path_for_embedded (old_path);
4448 case DataType::MIDI:
4449 /* XXX not implemented yet */
4453 if (new_path.empty()) {
4457 cerr << "Move " << old_path << " => " << new_path << endl;
4459 if (!copy_file (old_path, new_path)) {
4460 cerr << "failed !\n";
4464 /* make sure we stop looking in the external
4465 dir/folder. Remember, this is an all-or-nothing
4466 operations, it doesn't merge just some files.
4468 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4470 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4471 (*f)->set_path (new_path);
4476 save_state ("", false, false);
4482 bool accept_all_files (string const &, void *)
4488 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4490 /* 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.
4495 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4497 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4499 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4501 v.push_back (new_session_folder); /* full path */
4502 v.push_back (interchange_dir_name);
4503 v.push_back (new_session_path); /* just one directory/folder */
4504 v.push_back (typedir);
4505 v.push_back (Glib::path_get_basename (old_path));
4507 return Glib::build_filename (v);
4511 Session::save_as (SaveAs& saveas)
4513 vector<string> files;
4514 string current_folder = Glib::path_get_dirname (_path);
4515 string new_folder = legalize_for_path (saveas.new_name);
4516 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4517 int64_t total_bytes = 0;
4521 int32_t internal_file_cnt = 0;
4523 vector<string> do_not_copy_extensions;
4524 do_not_copy_extensions.push_back (statefile_suffix);
4525 do_not_copy_extensions.push_back (pending_suffix);
4526 do_not_copy_extensions.push_back (backup_suffix);
4527 do_not_copy_extensions.push_back (temp_suffix);
4528 do_not_copy_extensions.push_back (history_suffix);
4530 /* get total size */
4532 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4534 /* need to clear this because
4535 * find_files_matching_filter() is cumulative
4540 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4542 all += files.size();
4544 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4546 g_stat ((*i).c_str(), &gsb);
4547 total_bytes += gsb.st_size;
4551 /* save old values so we can switch back if we are not switching to the new session */
4553 string old_path = _path;
4554 string old_name = _name;
4555 string old_snapshot = _current_snapshot_name;
4556 string old_sd = _session_dir->root_path();
4557 vector<string> old_search_path[DataType::num_types];
4558 string old_config_search_path[DataType::num_types];
4560 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4561 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4562 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4563 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4565 /* switch session directory */
4567 (*_session_dir) = to_dir;
4569 /* create new tree */
4571 if (!_session_dir->create()) {
4572 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4577 /* copy all relevant files. Find each location in session_dirs,
4578 * and copy files from there to target.
4581 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4583 /* need to clear this because
4584 * find_files_matching_filter() is cumulative
4589 const size_t prefix_len = (*sd).path.size();
4591 /* Work just on the files within this session dir */
4593 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4595 /* add dir separator to protect against collisions with
4596 * track names (e.g. track named "audiofiles" or
4600 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4601 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4602 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4604 /* copy all the files. Handling is different for media files
4605 than others because of the *silly* subtree we have below the interchange
4606 folder. That really was a bad idea, but I'm not fixing it as part of
4607 implementing ::save_as().
4610 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4612 std::string from = *i;
4615 string filename = Glib::path_get_basename (from);
4616 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4617 if (filename == ".DS_STORE") {
4622 if (from.find (audiofile_dir_string) != string::npos) {
4624 /* audio file: only copy if asked */
4626 if (saveas.include_media && saveas.copy_media) {
4628 string to = make_new_media_path (*i, to_dir, new_folder);
4630 info << "media file copying from " << from << " to " << to << endmsg;
4632 if (!copy_file (from, to)) {
4633 throw Glib::FileError (Glib::FileError::IO_ERROR,
4634 string_compose(_("\ncopying \"%1\" failed !"), from));
4638 /* we found media files inside the session folder */
4640 internal_file_cnt++;
4642 } else if (from.find (midifile_dir_string) != string::npos) {
4644 /* midi file: always copy unless
4645 * creating an empty new session
4648 if (saveas.include_media) {
4650 string to = make_new_media_path (*i, to_dir, new_folder);
4652 info << "media file copying from " << from << " to " << to << endmsg;
4654 if (!copy_file (from, to)) {
4655 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4659 /* we found media files inside the session folder */
4661 internal_file_cnt++;
4663 } else if (from.find (analysis_dir_string) != string::npos) {
4665 /* make sure analysis dir exists in
4666 * new session folder, but we're not
4667 * copying analysis files here, see
4671 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4676 /* normal non-media file. Don't copy state, history, etc.
4679 bool do_copy = true;
4681 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4682 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4683 /* end of filename matches extension, do not copy file */
4689 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4690 /* don't copy peakfiles if
4691 * we're not copying media
4697 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4699 info << "attempting to make directory/folder " << to << endmsg;
4701 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4702 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4705 info << "attempting to copy " << from << " to " << to << endmsg;
4707 if (!copy_file (from, to)) {
4708 throw Glib::FileError (Glib::FileError::IO_ERROR,
4709 string_compose(_("\ncopying \"%1\" failed !"), from));
4714 /* measure file size even if we're not going to copy so that our Progress
4715 signals are correct, since we included these do-not-copy files
4716 in the computation of the total size and file count.
4720 g_stat (from.c_str(), &gsb);
4721 copied += gsb.st_size;
4724 double fraction = (double) copied / total_bytes;
4726 bool keep_going = true;
4728 if (saveas.copy_media) {
4730 /* no need or expectation of this if
4731 * media is not being copied, because
4732 * it will be fast(ish).
4735 /* tell someone "X percent, file M of N"; M is one-based */
4737 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4745 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4751 /* copy optional folders, if any */
4753 string old = plugins_dir ();
4754 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4755 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4756 copy_files (old, newdir);
4759 old = externals_dir ();
4760 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4761 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4762 copy_files (old, newdir);
4765 old = automation_dir ();
4766 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4767 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4768 copy_files (old, newdir);
4771 if (saveas.include_media) {
4773 if (saveas.copy_media) {
4774 #ifndef PLATFORM_WINDOWS
4775 /* There are problems with analysis files on
4776 * Windows, because they used a colon in their
4777 * names as late as 4.0. Colons are not legal
4778 * under Windows even if NTFS allows them.
4780 * This is a tricky problem to solve so for
4781 * just don't copy these files. They will be
4782 * regenerated as-needed anyway, subject to the
4783 * existing issue that the filenames will be
4784 * rejected by Windows, which is a separate
4785 * problem (though related).
4788 /* only needed if we are copying media, since the
4789 * analysis data refers to media data
4792 old = analysis_dir ();
4793 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4794 string newdir = Glib::build_filename (to_dir, "analysis");
4795 copy_files (old, newdir);
4797 #endif /* PLATFORM_WINDOWS */
4803 set_snapshot_name (saveas.new_name);
4804 _name = saveas.new_name;
4806 if (saveas.include_media && !saveas.copy_media) {
4808 /* reset search paths of the new session (which we're pretending to be right now) to
4809 include the original session search path, so we can still find all audio.
4812 if (internal_file_cnt) {
4813 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4814 ensure_search_path_includes (*s, DataType::AUDIO);
4815 cerr << "be sure to include " << *s << " for audio" << endl;
4818 /* we do not do this for MIDI because we copy
4819 all MIDI files if saveas.include_media is
4825 bool was_dirty = dirty ();
4827 save_state ("", false, false, !saveas.include_media);
4828 save_default_options ();
4830 if (saveas.copy_media && saveas.copy_external) {
4831 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4832 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4836 saveas.final_session_folder_name = _path;
4838 store_recent_sessions (_name, _path);
4840 if (!saveas.switch_to) {
4842 /* switch back to the way things were */
4846 set_snapshot_name (old_snapshot);
4848 (*_session_dir) = old_sd;
4854 if (internal_file_cnt) {
4855 /* reset these to their original values */
4856 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4857 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4862 /* prune session dirs, and update disk space statistics
4867 session_dirs.clear ();
4868 session_dirs.push_back (sp);
4869 refresh_disk_space ();
4871 /* ensure that all existing tracks reset their current capture source paths
4873 reset_write_sources (true, true);
4875 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4876 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4879 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4880 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4886 if (fs->within_session()) {
4887 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4888 fs->set_path (newpath);
4893 } catch (Glib::FileError& e) {
4895 saveas.failure_message = e.what();
4897 /* recursively remove all the directories */
4899 remove_directory (to_dir);
4907 saveas.failure_message = _("unknown reason");
4909 /* recursively remove all the directories */
4911 remove_directory (to_dir);
4921 static void set_progress (Progress* p, size_t n, size_t t)
4923 p->set_progress (float (n) / float(t));
4927 Session::archive_session (const std::string& dest,
4928 const std::string& name,
4929 ArchiveEncode compress_audio,
4930 bool only_used_sources,
4933 if (dest.empty () || name.empty ()) {
4937 /* save current values */
4938 bool was_dirty = dirty ();
4939 string old_path = _path;
4940 string old_name = _name;
4941 string old_snapshot = _current_snapshot_name;
4942 string old_sd = _session_dir->root_path();
4943 string old_config_search_path[DataType::num_types];
4944 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4945 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4947 /* ensure that session-path is included in search-path */
4949 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4950 if ((*sd).path == old_path) {
4958 /* create temporary dir to save session to */
4959 #ifdef PLATFORM_WINDOWS
4960 char tmp[256] = "C:\\TEMP\\";
4961 GetTempPath (sizeof (tmp), tmp);
4963 char const* tmp = getenv("TMPDIR");
4968 if ((strlen (tmp) + 21) > 1024) {
4973 strcpy (tmptpl, tmp);
4974 strcat (tmptpl, "ardourarchive-XXXXXX");
4975 char* tmpdir = g_mkdtemp (tmptpl);
4981 std::string to_dir = std::string (tmpdir);
4983 /* switch session directory temporarily */
4984 (*_session_dir) = to_dir;
4986 if (!_session_dir->create()) {
4987 (*_session_dir) = old_sd;
4988 remove_directory (to_dir);
4992 /* prepare archive */
4993 string archive = Glib::build_filename (dest, name + ".tar.xz");
4995 PBD::ScopedConnectionList progress_connection;
4996 PBD::FileArchive ar (archive);
4998 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5001 /* collect files to archive */
5002 std::map<string,string> filemap;
5004 vector<string> do_not_copy_extensions;
5005 do_not_copy_extensions.push_back (statefile_suffix);
5006 do_not_copy_extensions.push_back (pending_suffix);
5007 do_not_copy_extensions.push_back (backup_suffix);
5008 do_not_copy_extensions.push_back (temp_suffix);
5009 do_not_copy_extensions.push_back (history_suffix);
5011 vector<string> blacklist_dirs;
5012 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5013 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5014 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5015 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5016 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5017 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5019 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5021 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5022 if (only_used_sources) {
5023 playlists->sync_all_regions_with_regions ();
5024 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5027 // collect audio sources for this session, calc total size for encoding
5028 // add option to only include *used* sources (see Session::cleanup_sources)
5029 size_t total_size = 0;
5031 Glib::Threads::Mutex::Lock lm (source_lock);
5032 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5033 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5034 if (!afs || afs->readable_length () == 0) {
5038 if (only_used_sources) {
5042 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5047 std::string from = afs->path();
5049 if (compress_audio != NO_ENCODE) {
5050 total_size += afs->readable_length ();
5052 if (afs->within_session()) {
5053 filemap[from] = make_new_media_path (from, name, name);
5055 filemap[from] = make_new_media_path (from, name, name);
5056 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5063 if (compress_audio != NO_ENCODE) {
5065 progress->set_progress (2); // set to "encoding"
5066 progress->set_progress (0);
5069 Glib::Threads::Mutex::Lock lm (source_lock);
5070 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5071 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5072 if (!afs || afs->readable_length () == 0) {
5076 if (only_used_sources) {
5080 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5085 orig_sources[afs] = afs->path();
5087 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5088 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5089 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5092 progress->descend ((float)afs->readable_length () / total_size);
5096 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5097 afs->replace_file (new_path);
5100 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5104 progress->ascend ();
5110 progress->set_progress (-1); // set to "archiving"
5111 progress->set_progress (0);
5114 /* index files relevant for this session */
5115 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5116 vector<string> files;
5118 size_t prefix_len = (*sd).path.size();
5119 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5123 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5125 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5126 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5127 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5129 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5130 std::string from = *i;
5133 string filename = Glib::path_get_basename (from);
5134 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5135 if (filename == ".DS_STORE") {
5140 if (from.find (audiofile_dir_string) != string::npos) {
5142 } else if (from.find (midifile_dir_string) != string::npos) {
5143 filemap[from] = make_new_media_path (from, name, name);
5144 } else if (from.find (videofile_dir_string) != string::npos) {
5145 filemap[from] = make_new_media_path (from, name, name);
5147 bool do_copy = true;
5148 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5149 if (from.find (*v) != string::npos) {
5154 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5155 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5162 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5168 /* write session file */
5170 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5172 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5174 save_default_options ();
5176 size_t prefix_len = _path.size();
5177 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5181 /* collect session-state files */
5182 vector<string> files;
5183 do_not_copy_extensions.clear ();
5184 do_not_copy_extensions.push_back (history_suffix);
5186 blacklist_dirs.clear ();
5187 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5189 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5190 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5191 std::string from = *i;
5192 bool do_copy = true;
5193 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5194 if (from.find (*v) != string::npos) {
5199 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5200 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5206 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5210 /* restore original values */
5213 set_snapshot_name (old_snapshot);
5214 (*_session_dir) = old_sd;
5218 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5219 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5221 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5222 i->first->replace_file (i->second);
5225 int rv = ar.create (filemap);
5226 remove_directory (to_dir);
5232 Session::undo (uint32_t n)
5234 if (actively_recording()) {
5242 Session::redo (uint32_t n)
5244 if (actively_recording()) {