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 if ((child = find_named_node (root, "ProgramVersion")) != 0) {
1009 if ((prop = child->property ("modified-with")) != 0) {
1010 std::string modified_with = prop->value ();
1012 const double modified_with_version = atof (modified_with.substr ( modified_with.find(" ", 0) + 1, string::npos).c_str());
1013 const int modified_with_revision = atoi (modified_with.substr (modified_with.find("-", 0) + 1, string::npos).c_str());
1015 if (modified_with_version <= 5.3 && !(modified_with_version == 5.3 && modified_with_revision > 42)) {
1016 _midi_regions_use_bbt_beats = true;
1022 save_snapshot_name (snapshot_name);
1028 Session::load_options (const XMLNode& node)
1031 config.set_variables (node);
1036 Session::save_default_options ()
1038 return config.save_state();
1042 Session::get_state()
1048 Session::get_template()
1050 /* if we don't disable rec-enable, diskstreams
1051 will believe they need to store their capture
1052 sources in their state node.
1055 disable_record (false);
1057 return state(false);
1061 Session::state (bool full_state)
1064 XMLNode* node = new XMLNode("Session");
1068 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1069 node->add_property("version", buf);
1071 child = node->add_child ("ProgramVersion");
1072 child->add_property("created-with", created_with);
1074 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1075 child->add_property("modified-with", modified_with);
1077 /* store configuration settings */
1081 node->add_property ("name", _name);
1082 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1083 node->add_property ("sample-rate", buf);
1085 if (session_dirs.size() > 1) {
1089 vector<space_and_path>::iterator i = session_dirs.begin();
1090 vector<space_and_path>::iterator next;
1092 ++i; /* skip the first one */
1096 while (i != session_dirs.end()) {
1100 if (next != session_dirs.end()) {
1101 p += G_SEARCHPATH_SEPARATOR;
1110 child = node->add_child ("Path");
1111 child->add_content (p);
1115 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1117 /* save the ID counter */
1119 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1120 node->add_property ("id-counter", buf);
1122 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1123 node->add_property ("name-counter", buf);
1125 /* save the event ID counter */
1127 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1128 node->add_property ("event-counter", buf);
1130 /* save the VCA counter */
1132 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1133 node->add_property ("vca-counter", buf);
1135 /* various options */
1137 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1138 if (!midi_port_nodes.empty()) {
1139 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1140 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1141 midi_port_stuff->add_child_nocopy (**n);
1143 node->add_child_nocopy (*midi_port_stuff);
1146 node->add_child_nocopy (config.get_variables ());
1148 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1150 child = node->add_child ("Sources");
1153 Glib::Threads::Mutex::Lock sl (source_lock);
1155 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1157 /* Don't save information about non-file Sources, or
1158 * about non-destructive file sources that are empty
1159 * and unused by any regions.
1162 boost::shared_ptr<FileSource> fs;
1164 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1166 if (!fs->destructive()) {
1167 if (fs->empty() && !fs->used()) {
1172 child->add_child_nocopy (siter->second->get_state());
1177 child = node->add_child ("Regions");
1180 Glib::Threads::Mutex::Lock rl (region_lock);
1181 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1182 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1183 boost::shared_ptr<Region> r = i->second;
1184 /* only store regions not attached to playlists */
1185 if (r->playlist() == 0) {
1186 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1187 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1189 child->add_child_nocopy (r->get_state ());
1194 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1196 if (!cassocs.empty()) {
1197 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1199 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1201 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1202 i->first->id().print (buf, sizeof (buf));
1203 can->add_property (X_("copy"), buf);
1204 i->second->id().print (buf, sizeof (buf));
1205 can->add_property (X_("original"), buf);
1206 ca->add_child_nocopy (*can);
1216 node->add_child_nocopy (_locations->get_state());
1219 Locations loc (*this);
1220 // for a template, just create a new Locations, populate it
1221 // with the default start and end, and get the state for that.
1222 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1223 range->set (max_framepos, 0);
1225 XMLNode& locations_state = loc.get_state();
1227 if (ARDOUR::Profile->get_trx() && _locations) {
1228 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1229 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1230 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1231 locations_state.add_child_nocopy ((*i)->get_state ());
1235 node->add_child_nocopy (locations_state);
1238 child = node->add_child ("Bundles");
1240 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1241 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1242 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1244 child->add_child_nocopy (b->get_state());
1249 node->add_child_nocopy (_vca_manager->get_state());
1251 child = node->add_child ("Routes");
1253 boost::shared_ptr<RouteList> r = routes.reader ();
1255 RoutePublicOrderSorter cmp;
1256 RouteList public_order (*r);
1257 public_order.sort (cmp);
1259 /* the sort should have put the monitor out first */
1262 assert (_monitor_out == public_order.front());
1265 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1266 if (!(*i)->is_auditioner()) {
1268 child->add_child_nocopy ((*i)->get_state());
1270 child->add_child_nocopy ((*i)->get_template());
1276 playlists->add_state (node, full_state);
1278 child = node->add_child ("RouteGroups");
1279 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1280 child->add_child_nocopy ((*i)->get_state());
1284 XMLNode* gain_child = node->add_child ("Click");
1285 gain_child->add_child_nocopy (_click_io->state (full_state));
1286 gain_child->add_child_nocopy (_click_gain->state (full_state));
1290 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1291 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1295 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1296 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1299 node->add_child_nocopy (_speakers->get_state());
1300 node->add_child_nocopy (_tempo_map->get_state());
1301 node->add_child_nocopy (get_control_protocol_state());
1304 node->add_child_copy (*_extra_xml);
1308 Glib::Threads::Mutex::Lock lm (lua_lock);
1311 luabridge::LuaRef savedstate ((*_lua_save)());
1312 saved = savedstate.cast<std::string>();
1314 lua.collect_garbage ();
1317 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1318 std::string b64s (b64);
1321 XMLNode* script_node = new XMLNode (X_("Script"));
1322 script_node->add_property (X_("lua"), LUA_VERSION);
1323 script_node->add_content (b64s);
1324 node->add_child_nocopy (*script_node);
1331 Session::get_control_protocol_state ()
1333 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1334 return cpm.get_state();
1338 Session::set_state (const XMLNode& node, int version)
1343 XMLProperty const * prop;
1346 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1348 if (node.name() != X_("Session")) {
1349 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1353 if ((prop = node.property ("name")) != 0) {
1354 _name = prop->value ();
1357 if ((prop = node.property (X_("sample-rate"))) != 0) {
1359 _base_frame_rate = atoi (prop->value());
1360 _nominal_frame_rate = _base_frame_rate;
1362 assert (AudioEngine::instance()->running ());
1363 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1364 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1365 if (r.get_value_or (0)) {
1371 created_with = "unknown";
1372 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1373 if ((prop = child->property (X_("created-with"))) != 0) {
1374 created_with = prop->value ();
1378 setup_raid_path(_session_dir->root_path());
1380 if ((prop = node.property (X_("end-is-free"))) != 0) {
1381 _session_range_end_is_free = string_is_affirmative (prop->value());
1384 if ((prop = node.property (X_("id-counter"))) != 0) {
1386 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1387 ID::init_counter (x);
1389 /* old sessions used a timebased counter, so fake
1390 the startup ID counter based on a standard
1395 ID::init_counter (now);
1398 if ((prop = node.property (X_("name-counter"))) != 0) {
1399 init_name_id_counter (atoi (prop->value()));
1402 if ((prop = node.property (X_("event-counter"))) != 0) {
1403 Evoral::init_event_id_counter (atoi (prop->value()));
1406 if ((prop = node.property (X_("vca-counter"))) != 0) {
1408 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1409 VCA::set_next_vca_number (x);
1411 VCA::set_next_vca_number (1);
1414 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1415 _midi_ports->set_midi_port_states (child->children());
1418 IO::disable_connecting ();
1420 Stateful::save_extra_xml (node);
1422 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1423 load_options (*child);
1424 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1425 load_options (*child);
1427 error << _("Session: XML state has no options section") << endmsg;
1430 if (version >= 3000) {
1431 if ((child = find_named_node (node, "Metadata")) == 0) {
1432 warning << _("Session: XML state has no metadata section") << endmsg;
1433 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1438 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1439 _speakers->set_state (*child, version);
1442 if ((child = find_named_node (node, "Sources")) == 0) {
1443 error << _("Session: XML state has no sources section") << endmsg;
1445 } else if (load_sources (*child)) {
1449 if ((child = find_named_node (node, "TempoMap")) == 0) {
1450 error << _("Session: XML state has no Tempo Map section") << endmsg;
1452 } else if (_tempo_map->set_state (*child, version)) {
1456 if ((child = find_named_node (node, "Locations")) == 0) {
1457 error << _("Session: XML state has no locations section") << endmsg;
1459 } else if (_locations->set_state (*child, version)) {
1463 locations_changed ();
1465 if (_session_range_location) {
1466 AudioFileSource::set_header_position_offset (_session_range_location->start());
1469 if ((child = find_named_node (node, "Regions")) == 0) {
1470 error << _("Session: XML state has no Regions section") << endmsg;
1472 } else if (load_regions (*child)) {
1476 if ((child = find_named_node (node, "Playlists")) == 0) {
1477 error << _("Session: XML state has no playlists section") << endmsg;
1479 } else if (playlists->load (*this, *child)) {
1483 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1485 } else if (playlists->load_unused (*this, *child)) {
1489 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1490 if (load_compounds (*child)) {
1495 if (version >= 3000) {
1496 if ((child = find_named_node (node, "Bundles")) == 0) {
1497 warning << _("Session: XML state has no bundles section") << endmsg;
1500 /* We can't load Bundles yet as they need to be able
1501 to convert from port names to Port objects, which can't happen until
1503 _bundle_xml_node = new XMLNode (*child);
1507 if (version < 3000) {
1508 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1509 error << _("Session: XML state has no diskstreams section") << endmsg;
1511 } else if (load_diskstreams_2X (*child, version)) {
1516 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1517 _vca_manager->set_state (*child, version);
1520 if ((child = find_named_node (node, "Routes")) == 0) {
1521 error << _("Session: XML state has no routes section") << endmsg;
1523 } else if (load_routes (*child, version)) {
1527 /* Now that we have Routes and masters loaded, connect them if appropriate */
1529 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1531 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1532 _diskstreams_2X.clear ();
1534 if (version >= 3000) {
1536 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1537 error << _("Session: XML state has no route groups section") << endmsg;
1539 } else if (load_route_groups (*child, version)) {
1543 } else if (version < 3000) {
1545 if ((child = find_named_node (node, "EditGroups")) == 0) {
1546 error << _("Session: XML state has no edit groups section") << endmsg;
1548 } else if (load_route_groups (*child, version)) {
1552 if ((child = find_named_node (node, "MixGroups")) == 0) {
1553 error << _("Session: XML state has no mix groups section") << endmsg;
1555 } else if (load_route_groups (*child, version)) {
1560 if ((child = find_named_node (node, "Click")) == 0) {
1561 warning << _("Session: XML state has no click section") << endmsg;
1562 } else if (_click_io) {
1563 setup_click_state (&node);
1566 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1567 ControlProtocolManager::instance().set_state (*child, version);
1570 if ((child = find_named_node (node, "Script"))) {
1571 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1572 if (!(*n)->is_content ()) { continue; }
1574 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1576 Glib::Threads::Mutex::Lock lm (lua_lock);
1577 (*_lua_load)(std::string ((const char*)buf, size));
1578 } catch (luabridge::LuaException const& e) {
1579 cerr << "LuaException:" << e.what () << endl;
1585 update_route_record_state ();
1587 /* here beginneth the second phase ... */
1588 set_snapshot_name (_current_snapshot_name);
1590 StateReady (); /* EMIT SIGNAL */
1603 Session::load_routes (const XMLNode& node, int version)
1606 XMLNodeConstIterator niter;
1607 RouteList new_routes;
1609 nlist = node.children();
1613 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1615 boost::shared_ptr<Route> route;
1616 if (version < 3000) {
1617 route = XMLRouteFactory_2X (**niter, version);
1619 route = XMLRouteFactory (**niter, version);
1623 error << _("Session: cannot create Route from XML description.") << endmsg;
1627 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1629 new_routes.push_back (route);
1632 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1634 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1636 BootMessage (_("Finished adding tracks/busses"));
1641 boost::shared_ptr<Route>
1642 Session::XMLRouteFactory (const XMLNode& node, int version)
1644 boost::shared_ptr<Route> ret;
1646 if (node.name() != "Route") {
1650 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1652 DataType type = DataType::AUDIO;
1653 XMLProperty const * prop = node.property("default-type");
1656 type = DataType (prop->value());
1659 assert (type != DataType::NIL);
1663 boost::shared_ptr<Track> track;
1665 if (type == DataType::AUDIO) {
1666 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1668 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1671 if (track->init()) {
1675 if (track->set_state (node, version)) {
1679 BOOST_MARK_TRACK (track);
1683 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1684 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1686 if (r->init () == 0 && r->set_state (node, version) == 0) {
1687 BOOST_MARK_ROUTE (r);
1695 boost::shared_ptr<Route>
1696 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1698 boost::shared_ptr<Route> ret;
1700 if (node.name() != "Route") {
1704 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1706 ds_prop = node.property (X_("diskstream"));
1709 DataType type = DataType::AUDIO;
1710 XMLProperty const * prop = node.property("default-type");
1713 type = DataType (prop->value());
1716 assert (type != DataType::NIL);
1720 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1721 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1725 if (i == _diskstreams_2X.end()) {
1726 error << _("Could not find diskstream for route") << endmsg;
1727 return boost::shared_ptr<Route> ();
1730 boost::shared_ptr<Track> track;
1732 if (type == DataType::AUDIO) {
1733 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1735 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1738 if (track->init()) {
1742 if (track->set_state (node, version)) {
1746 track->set_diskstream (*i);
1748 BOOST_MARK_TRACK (track);
1752 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1753 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1755 if (r->init () == 0 && r->set_state (node, version) == 0) {
1756 BOOST_MARK_ROUTE (r);
1765 Session::load_regions (const XMLNode& node)
1768 XMLNodeConstIterator niter;
1769 boost::shared_ptr<Region> region;
1771 nlist = node.children();
1775 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1776 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1777 error << _("Session: cannot create Region from XML description.");
1778 XMLProperty const * name = (**niter).property("name");
1781 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1792 Session::load_compounds (const XMLNode& node)
1794 XMLNodeList calist = node.children();
1795 XMLNodeConstIterator caiter;
1796 XMLProperty const * caprop;
1798 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1799 XMLNode* ca = *caiter;
1803 if ((caprop = ca->property (X_("original"))) == 0) {
1806 orig_id = caprop->value();
1808 if ((caprop = ca->property (X_("copy"))) == 0) {
1811 copy_id = caprop->value();
1813 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1814 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1816 if (!orig || !copy) {
1817 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1823 RegionFactory::add_compound_association (orig, copy);
1830 Session::load_nested_sources (const XMLNode& node)
1833 XMLNodeConstIterator niter;
1835 nlist = node.children();
1837 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1838 if ((*niter)->name() == "Source") {
1840 /* it may already exist, so don't recreate it unnecessarily
1843 XMLProperty const * prop = (*niter)->property (X_("id"));
1845 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1849 ID source_id (prop->value());
1851 if (!source_by_id (source_id)) {
1854 SourceFactory::create (*this, **niter, true);
1856 catch (failed_constructor& err) {
1857 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1864 boost::shared_ptr<Region>
1865 Session::XMLRegionFactory (const XMLNode& node, bool full)
1867 XMLProperty const * type = node.property("type");
1871 const XMLNodeList& nlist = node.children();
1873 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1874 XMLNode *child = (*niter);
1875 if (child->name() == "NestedSource") {
1876 load_nested_sources (*child);
1880 if (!type || type->value() == "audio") {
1881 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1882 } else if (type->value() == "midi") {
1883 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1886 } catch (failed_constructor& err) {
1887 return boost::shared_ptr<Region> ();
1890 return boost::shared_ptr<Region> ();
1893 boost::shared_ptr<AudioRegion>
1894 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1896 XMLProperty const * prop;
1897 boost::shared_ptr<Source> source;
1898 boost::shared_ptr<AudioSource> as;
1900 SourceList master_sources;
1901 uint32_t nchans = 1;
1904 if (node.name() != X_("Region")) {
1905 return boost::shared_ptr<AudioRegion>();
1908 if ((prop = node.property (X_("channels"))) != 0) {
1909 nchans = atoi (prop->value().c_str());
1912 if ((prop = node.property ("name")) == 0) {
1913 cerr << "no name for this region\n";
1917 if ((prop = node.property (X_("source-0"))) == 0) {
1918 if ((prop = node.property ("source")) == 0) {
1919 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1920 return boost::shared_ptr<AudioRegion>();
1924 PBD::ID s_id (prop->value());
1926 if ((source = source_by_id (s_id)) == 0) {
1927 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1928 return boost::shared_ptr<AudioRegion>();
1931 as = boost::dynamic_pointer_cast<AudioSource>(source);
1933 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1934 return boost::shared_ptr<AudioRegion>();
1937 sources.push_back (as);
1939 /* pickup other channels */
1941 for (uint32_t n=1; n < nchans; ++n) {
1942 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1943 if ((prop = node.property (buf)) != 0) {
1945 PBD::ID id2 (prop->value());
1947 if ((source = source_by_id (id2)) == 0) {
1948 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1949 return boost::shared_ptr<AudioRegion>();
1952 as = boost::dynamic_pointer_cast<AudioSource>(source);
1954 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1955 return boost::shared_ptr<AudioRegion>();
1957 sources.push_back (as);
1961 for (uint32_t n = 0; n < nchans; ++n) {
1962 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1963 if ((prop = node.property (buf)) != 0) {
1965 PBD::ID id2 (prop->value());
1967 if ((source = source_by_id (id2)) == 0) {
1968 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1969 return boost::shared_ptr<AudioRegion>();
1972 as = boost::dynamic_pointer_cast<AudioSource>(source);
1974 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1975 return boost::shared_ptr<AudioRegion>();
1977 master_sources.push_back (as);
1982 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1984 /* a final detail: this is the one and only place that we know how long missing files are */
1986 if (region->whole_file()) {
1987 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1988 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1990 sfp->set_length (region->length());
1995 if (!master_sources.empty()) {
1996 if (master_sources.size() != nchans) {
1997 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1999 region->set_master_sources (master_sources);
2007 catch (failed_constructor& err) {
2008 return boost::shared_ptr<AudioRegion>();
2012 boost::shared_ptr<MidiRegion>
2013 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2015 XMLProperty const * prop;
2016 boost::shared_ptr<Source> source;
2017 boost::shared_ptr<MidiSource> ms;
2020 if (node.name() != X_("Region")) {
2021 return boost::shared_ptr<MidiRegion>();
2024 if ((prop = node.property ("name")) == 0) {
2025 cerr << "no name for this region\n";
2029 if ((prop = node.property (X_("source-0"))) == 0) {
2030 if ((prop = node.property ("source")) == 0) {
2031 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2032 return boost::shared_ptr<MidiRegion>();
2036 PBD::ID s_id (prop->value());
2038 if ((source = source_by_id (s_id)) == 0) {
2039 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2040 return boost::shared_ptr<MidiRegion>();
2043 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2045 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2046 return boost::shared_ptr<MidiRegion>();
2049 sources.push_back (ms);
2052 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2053 /* a final detail: this is the one and only place that we know how long missing files are */
2055 if (region->whole_file()) {
2056 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2057 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2059 sfp->set_length (region->length());
2067 catch (failed_constructor& err) {
2068 return boost::shared_ptr<MidiRegion>();
2073 Session::get_sources_as_xml ()
2076 XMLNode* node = new XMLNode (X_("Sources"));
2077 Glib::Threads::Mutex::Lock lm (source_lock);
2079 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2080 node->add_child_nocopy (i->second->get_state());
2087 Session::reset_write_sources (bool mark_write_complete, bool force)
2089 boost::shared_ptr<RouteList> rl = routes.reader();
2090 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2091 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2093 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2094 tr->reset_write_sources(mark_write_complete, force);
2095 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2101 Session::load_sources (const XMLNode& node)
2104 XMLNodeConstIterator niter;
2105 boost::shared_ptr<Source> source; /* don't need this but it stops some
2106 * versions of gcc complaining about
2107 * discarded return values.
2110 nlist = node.children();
2114 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2117 if ((source = XMLSourceFactory (**niter)) == 0) {
2118 error << _("Session: cannot create Source from XML description.") << endmsg;
2121 } catch (MissingSource& err) {
2125 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2126 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2127 PROGRAM_NAME) << endmsg;
2131 if (!no_questions_about_missing_files) {
2132 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2137 switch (user_choice) {
2139 /* user added a new search location, so try again */
2144 /* user asked to quit the entire session load
2149 no_questions_about_missing_files = true;
2153 no_questions_about_missing_files = true;
2160 case DataType::AUDIO:
2161 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2164 case DataType::MIDI:
2165 /* The MIDI file is actually missing so
2166 * just create a new one in the same
2167 * location. Do not announce its
2171 if (!Glib::path_is_absolute (err.path)) {
2172 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2174 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2179 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2180 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2181 /* reset ID to match the missing one */
2182 source->set_id (**niter);
2183 /* Now we can announce it */
2184 SourceFactory::SourceCreated (source);
2195 boost::shared_ptr<Source>
2196 Session::XMLSourceFactory (const XMLNode& node)
2198 if (node.name() != "Source") {
2199 return boost::shared_ptr<Source>();
2203 /* note: do peak building in another thread when loading session state */
2204 return SourceFactory::create (*this, node, true);
2207 catch (failed_constructor& err) {
2208 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2209 return boost::shared_ptr<Source>();
2214 Session::save_template (string template_name, bool replace_existing)
2216 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2220 bool absolute_path = Glib::path_is_absolute (template_name);
2222 /* directory to put the template in */
2223 std::string template_dir_path;
2225 if (!absolute_path) {
2226 std::string user_template_dir(user_template_directory());
2228 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2229 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2230 user_template_dir, g_strerror (errno)) << endmsg;
2234 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2236 template_dir_path = template_name;
2239 if (!ARDOUR::Profile->get_trx()) {
2240 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2241 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2242 template_dir_path) << endmsg;
2246 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2247 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2248 template_dir_path, g_strerror (errno)) << endmsg;
2254 std::string template_file_path;
2256 if (ARDOUR::Profile->get_trx()) {
2257 template_file_path = template_name;
2259 if (absolute_path) {
2260 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2262 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2266 SessionSaveUnderway (); /* EMIT SIGNAL */
2271 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2272 tree.set_root (&get_template());
2275 if (!tree.write (template_file_path)) {
2276 error << _("template not saved") << endmsg;
2280 store_recent_templates (template_file_path);
2286 Session::refresh_disk_space ()
2288 #if __APPLE__ || __FreeBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2290 Glib::Threads::Mutex::Lock lm (space_lock);
2292 /* get freespace on every FS that is part of the session path */
2294 _total_free_4k_blocks = 0;
2295 _total_free_4k_blocks_uncertain = false;
2297 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2299 struct statfs statfsbuf;
2300 statfs (i->path.c_str(), &statfsbuf);
2302 double const scale = statfsbuf.f_bsize / 4096.0;
2304 /* See if this filesystem is read-only */
2305 struct statvfs statvfsbuf;
2306 statvfs (i->path.c_str(), &statvfsbuf);
2308 /* f_bavail can be 0 if it is undefined for whatever
2309 filesystem we are looking at; Samba shares mounted
2310 via GVFS are an example of this.
2312 if (statfsbuf.f_bavail == 0) {
2313 /* block count unknown */
2315 i->blocks_unknown = true;
2316 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2317 /* read-only filesystem */
2319 i->blocks_unknown = false;
2321 /* read/write filesystem with known space */
2322 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2323 i->blocks_unknown = false;
2326 _total_free_4k_blocks += i->blocks;
2327 if (i->blocks_unknown) {
2328 _total_free_4k_blocks_uncertain = true;
2331 #elif defined PLATFORM_WINDOWS
2332 vector<string> scanned_volumes;
2333 vector<string>::iterator j;
2334 vector<space_and_path>::iterator i;
2335 DWORD nSectorsPerCluster, nBytesPerSector,
2336 nFreeClusters, nTotalClusters;
2340 _total_free_4k_blocks = 0;
2342 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2343 strncpy (disk_drive, (*i).path.c_str(), 3);
2347 volume_found = false;
2348 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2350 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2351 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2352 i->blocks = (uint32_t)(nFreeBytes / 4096);
2354 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2355 if (0 == j->compare(disk_drive)) {
2356 volume_found = true;
2361 if (!volume_found) {
2362 scanned_volumes.push_back(disk_drive);
2363 _total_free_4k_blocks += i->blocks;
2368 if (0 == _total_free_4k_blocks) {
2369 strncpy (disk_drive, path().c_str(), 3);
2372 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2374 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2375 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2376 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2383 Session::get_best_session_directory_for_new_audio ()
2385 vector<space_and_path>::iterator i;
2386 string result = _session_dir->root_path();
2388 /* handle common case without system calls */
2390 if (session_dirs.size() == 1) {
2394 /* OK, here's the algorithm we're following here:
2396 We want to select which directory to use for
2397 the next file source to be created. Ideally,
2398 we'd like to use a round-robin process so as to
2399 get maximum performance benefits from splitting
2400 the files across multiple disks.
2402 However, in situations without much diskspace, an
2403 RR approach may end up filling up a filesystem
2404 with new files while others still have space.
2405 Its therefore important to pay some attention to
2406 the freespace in the filesystem holding each
2407 directory as well. However, if we did that by
2408 itself, we'd keep creating new files in the file
2409 system with the most space until it was as full
2410 as all others, thus negating any performance
2411 benefits of this RAID-1 like approach.
2413 So, we use a user-configurable space threshold. If
2414 there are at least 2 filesystems with more than this
2415 much space available, we use RR selection between them.
2416 If not, then we pick the filesystem with the most space.
2418 This gets a good balance between the two
2422 refresh_disk_space ();
2424 int free_enough = 0;
2426 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2427 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2432 if (free_enough >= 2) {
2433 /* use RR selection process, ensuring that the one
2437 i = last_rr_session_dir;
2440 if (++i == session_dirs.end()) {
2441 i = session_dirs.begin();
2444 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2445 SessionDirectory sdir(i->path);
2446 if (sdir.create ()) {
2448 last_rr_session_dir = i;
2453 } while (i != last_rr_session_dir);
2457 /* pick FS with the most freespace (and that
2458 seems to actually work ...)
2461 vector<space_and_path> sorted;
2462 space_and_path_ascending_cmp cmp;
2464 sorted = session_dirs;
2465 sort (sorted.begin(), sorted.end(), cmp);
2467 for (i = sorted.begin(); i != sorted.end(); ++i) {
2468 SessionDirectory sdir(i->path);
2469 if (sdir.create ()) {
2471 last_rr_session_dir = i;
2481 Session::automation_dir () const
2483 return Glib::build_filename (_path, automation_dir_name);
2487 Session::analysis_dir () const
2489 return Glib::build_filename (_path, analysis_dir_name);
2493 Session::plugins_dir () const
2495 return Glib::build_filename (_path, plugins_dir_name);
2499 Session::externals_dir () const
2501 return Glib::build_filename (_path, externals_dir_name);
2505 Session::load_bundles (XMLNode const & node)
2507 XMLNodeList nlist = node.children();
2508 XMLNodeConstIterator niter;
2512 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2513 if ((*niter)->name() == "InputBundle") {
2514 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2515 } else if ((*niter)->name() == "OutputBundle") {
2516 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2518 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2527 Session::load_route_groups (const XMLNode& node, int version)
2529 XMLNodeList nlist = node.children();
2530 XMLNodeConstIterator niter;
2534 if (version >= 3000) {
2536 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2537 if ((*niter)->name() == "RouteGroup") {
2538 RouteGroup* rg = new RouteGroup (*this, "");
2539 add_route_group (rg);
2540 rg->set_state (**niter, version);
2544 } else if (version < 3000) {
2546 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2547 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2548 RouteGroup* rg = new RouteGroup (*this, "");
2549 add_route_group (rg);
2550 rg->set_state (**niter, version);
2559 state_file_filter (const string &str, void* /*arg*/)
2561 return (str.length() > strlen(statefile_suffix) &&
2562 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2566 remove_end(string state)
2568 string statename(state);
2570 string::size_type start,end;
2571 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2572 statename = statename.substr (start+1);
2575 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2576 end = statename.length();
2579 return string(statename.substr (0, end));
2583 Session::possible_states (string path)
2585 vector<string> states;
2586 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2588 transform(states.begin(), states.end(), states.begin(), remove_end);
2590 sort (states.begin(), states.end());
2596 Session::possible_states () const
2598 return possible_states(_path);
2602 Session::add_route_group (RouteGroup* g)
2604 _route_groups.push_back (g);
2605 route_group_added (g); /* EMIT SIGNAL */
2607 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2608 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2609 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2615 Session::remove_route_group (RouteGroup& rg)
2617 list<RouteGroup*>::iterator i;
2619 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2620 _route_groups.erase (i);
2623 route_group_removed (); /* EMIT SIGNAL */
2627 /** Set a new order for our route groups, without adding or removing any.
2628 * @param groups Route group list in the new order.
2631 Session::reorder_route_groups (list<RouteGroup*> groups)
2633 _route_groups = groups;
2635 route_groups_reordered (); /* EMIT SIGNAL */
2641 Session::route_group_by_name (string name)
2643 list<RouteGroup *>::iterator i;
2645 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2646 if ((*i)->name() == name) {
2654 Session::all_route_group() const
2656 return *_all_route_group;
2660 Session::add_commands (vector<Command*> const & cmds)
2662 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2668 Session::add_command (Command* const cmd)
2670 assert (_current_trans);
2671 DEBUG_UNDO_HISTORY (
2672 string_compose ("Current Undo Transaction %1, adding command: %2",
2673 _current_trans->name (),
2675 _current_trans->add_command (cmd);
2678 PBD::StatefulDiffCommand*
2679 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2681 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2687 Session::begin_reversible_command (const string& name)
2689 begin_reversible_command (g_quark_from_string (name.c_str ()));
2692 /** Begin a reversible command using a GQuark to identify it.
2693 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2694 * but there must be as many begin...()s as there are commit...()s.
2697 Session::begin_reversible_command (GQuark q)
2699 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2700 to hold all the commands that are committed. This keeps the order of
2701 commands correct in the history.
2704 if (_current_trans == 0) {
2705 DEBUG_UNDO_HISTORY (string_compose (
2706 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2708 /* start a new transaction */
2709 assert (_current_trans_quarks.empty ());
2710 _current_trans = new UndoTransaction();
2711 _current_trans->set_name (g_quark_to_string (q));
2713 DEBUG_UNDO_HISTORY (
2714 string_compose ("Begin Reversible Command, current transaction: %1",
2715 _current_trans->name ()));
2718 _current_trans_quarks.push_front (q);
2722 Session::abort_reversible_command ()
2724 if (_current_trans != 0) {
2725 DEBUG_UNDO_HISTORY (
2726 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2727 _current_trans->clear();
2728 delete _current_trans;
2730 _current_trans_quarks.clear();
2735 Session::commit_reversible_command (Command *cmd)
2737 assert (_current_trans);
2738 assert (!_current_trans_quarks.empty ());
2743 DEBUG_UNDO_HISTORY (
2744 string_compose ("Current Undo Transaction %1, adding command: %2",
2745 _current_trans->name (),
2747 _current_trans->add_command (cmd);
2750 DEBUG_UNDO_HISTORY (
2751 string_compose ("Commit Reversible Command, current transaction: %1",
2752 _current_trans->name ()));
2754 _current_trans_quarks.pop_front ();
2756 if (!_current_trans_quarks.empty ()) {
2757 DEBUG_UNDO_HISTORY (
2758 string_compose ("Commit Reversible Command, transaction is not "
2759 "top-level, current transaction: %1",
2760 _current_trans->name ()));
2761 /* the transaction we're committing is not the top-level one */
2765 if (_current_trans->empty()) {
2766 /* no commands were added to the transaction, so just get rid of it */
2767 DEBUG_UNDO_HISTORY (
2768 string_compose ("Commit Reversible Command, No commands were "
2769 "added to current transaction: %1",
2770 _current_trans->name ()));
2771 delete _current_trans;
2776 gettimeofday (&now, 0);
2777 _current_trans->set_timestamp (now);
2779 _history.add (_current_trans);
2784 accept_all_audio_files (const string& path, void* /*arg*/)
2786 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2790 if (!AudioFileSource::safe_audio_file_extension (path)) {
2798 accept_all_midi_files (const string& path, void* /*arg*/)
2800 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2804 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2805 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2806 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2810 accept_all_state_files (const string& path, void* /*arg*/)
2812 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2816 std::string const statefile_ext (statefile_suffix);
2817 if (path.length() >= statefile_ext.length()) {
2818 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2825 Session::find_all_sources (string path, set<string>& result)
2830 if (!tree.read (path)) {
2834 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2839 XMLNodeConstIterator niter;
2841 nlist = node->children();
2845 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2847 XMLProperty const * prop;
2849 if ((prop = (*niter)->property (X_("type"))) == 0) {
2853 DataType type (prop->value());
2855 if ((prop = (*niter)->property (X_("name"))) == 0) {
2859 if (Glib::path_is_absolute (prop->value())) {
2860 /* external file, ignore */
2868 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2869 result.insert (found_path);
2877 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2879 vector<string> state_files;
2881 string this_snapshot_path;
2887 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2888 ripped = ripped.substr (0, ripped.length() - 1);
2891 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2893 if (state_files.empty()) {
2898 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2899 this_snapshot_path += statefile_suffix;
2901 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2903 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2905 if (exclude_this_snapshot && *i == this_snapshot_path) {
2906 cerr << "\texcluded\n";
2911 if (find_all_sources (*i, result) < 0) {
2919 struct RegionCounter {
2920 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2921 AudioSourceList::iterator iter;
2922 boost::shared_ptr<Region> region;
2925 RegionCounter() : count (0) {}
2929 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2931 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2932 return r.get_value_or (1);
2936 Session::cleanup_regions ()
2938 bool removed = false;
2939 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2941 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2943 uint32_t used = playlists->region_use_count (i->second);
2945 if (used == 0 && !i->second->automatic ()) {
2946 boost::weak_ptr<Region> w = i->second;
2949 RegionFactory::map_remove (w);
2956 // re-check to remove parent references of compound regions
2957 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2958 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2962 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2963 if (0 == playlists->region_use_count (i->second)) {
2964 boost::weak_ptr<Region> w = i->second;
2966 RegionFactory::map_remove (w);
2973 /* dump the history list */
2980 Session::can_cleanup_peakfiles () const
2982 if (deletion_in_progress()) {
2985 if (!_writable || (_state_of_the_state & CannotSave)) {
2986 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2989 if (record_status() == Recording) {
2990 error << _("Cannot cleanup peak-files while recording") << endmsg;
2997 Session::cleanup_peakfiles ()
2999 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3004 assert (can_cleanup_peakfiles ());
3005 assert (!peaks_cleanup_in_progres());
3007 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3009 int timeout = 5000; // 5 seconds
3010 while (!SourceFactory::files_with_peaks.empty()) {
3011 Glib::usleep (1000);
3012 if (--timeout < 0) {
3013 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3014 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3019 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3020 boost::shared_ptr<AudioSource> as;
3021 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3022 as->close_peakfile();
3026 PBD::clear_directory (session_directory().peak_path());
3028 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3030 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3031 boost::shared_ptr<AudioSource> as;
3032 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3033 SourceFactory::setup_peakfile(as, true);
3040 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3042 pl->deep_sources (*all_sources);
3046 Session::cleanup_sources (CleanupReport& rep)
3048 // FIXME: needs adaptation to midi
3050 vector<boost::shared_ptr<Source> > dead_sources;
3053 vector<string> candidates;
3054 vector<string> unused;
3055 set<string> sources_used_by_all_snapshots;
3062 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3064 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3066 /* this is mostly for windows which doesn't allow file
3067 * renaming if the file is in use. But we don't special
3068 * case it because we need to know if this causes
3069 * problems, and the easiest way to notice that is to
3070 * keep it in place for all platforms.
3073 request_stop (false);
3075 _butler->wait_until_finished ();
3077 /* consider deleting all unused playlists */
3079 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3084 /* sync the "all regions" property of each playlist with its current state
3087 playlists->sync_all_regions_with_regions ();
3089 /* find all un-used sources */
3094 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3096 SourceMap::iterator tmp;
3101 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3105 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3106 dead_sources.push_back (i->second);
3107 i->second->drop_references ();
3113 /* build a list of all the possible audio directories for the session */
3115 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3116 SessionDirectory sdir ((*i).path);
3117 asp += sdir.sound_path();
3119 audio_path += asp.to_string();
3122 /* build a list of all the possible midi directories for the session */
3124 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3125 SessionDirectory sdir ((*i).path);
3126 msp += sdir.midi_path();
3128 midi_path += msp.to_string();
3130 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3131 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3133 /* add sources from all other snapshots as "used", but don't use this
3134 snapshot because the state file on disk still references sources we
3135 may have already dropped.
3138 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3140 /* Although the region factory has a list of all regions ever created
3141 * for this session, we're only interested in regions actually in
3142 * playlists right now. So merge all playlist regions lists together.
3144 * This will include the playlists used within compound regions.
3147 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3149 /* add our current source list
3152 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3153 boost::shared_ptr<FileSource> fs;
3154 SourceMap::iterator tmp = i;
3157 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3163 /* this is mostly for windows which doesn't allow file
3164 * renaming if the file is in use. But we do not special
3165 * case it because we need to know if this causes
3166 * problems, and the easiest way to notice that is to
3167 * keep it in place for all platforms.
3172 if (!fs->is_stub()) {
3174 /* Note that we're checking a list of all
3175 * sources across all snapshots with the list
3176 * of sources used by this snapshot.
3179 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3180 /* this source is in use by this snapshot */
3181 sources_used_by_all_snapshots.insert (fs->path());
3182 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3184 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3185 /* this source is NOT in use by this snapshot
3188 /* remove all related regions from RegionFactory master list
3191 RegionFactory::remove_regions_using_source (i->second);
3193 /* remove from our current source list
3194 * also. We may not remove it from
3195 * disk, because it may be used by
3196 * other snapshots, but it isn't used inside this
3197 * snapshot anymore, so we don't need a
3208 /* now check each candidate source to see if it exists in the list of
3209 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3212 cerr << "Candidates: " << candidates.size() << endl;
3213 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3215 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3220 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3222 tmppath1 = canonical_path (spath);
3223 tmppath2 = canonical_path ((*i));
3225 cerr << "\t => " << tmppath2 << endl;
3227 if (tmppath1 == tmppath2) {
3234 unused.push_back (spath);
3238 cerr << "Actually unused: " << unused.size() << endl;
3240 if (unused.empty()) {
3246 /* now try to move all unused files into the "dead" directory(ies) */
3248 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3253 /* don't move the file across filesystems, just
3254 stick it in the `dead_dir_name' directory
3255 on whichever filesystem it was already on.
3258 if ((*x).find ("/sounds/") != string::npos) {
3260 /* old school, go up 1 level */
3262 newpath = Glib::path_get_dirname (*x); // "sounds"
3263 newpath = Glib::path_get_dirname (newpath); // "session-name"
3267 /* new school, go up 4 levels */
3269 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3270 newpath = Glib::path_get_dirname (newpath); // "session-name"
3271 newpath = Glib::path_get_dirname (newpath); // "interchange"
3272 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3275 newpath = Glib::build_filename (newpath, dead_dir_name);
3277 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3278 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3282 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3284 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3286 /* the new path already exists, try versioning */
3288 char buf[PATH_MAX+1];
3292 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3295 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3296 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3300 if (version == 999) {
3301 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3305 newpath = newpath_v;
3310 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3311 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3312 newpath, g_strerror (errno)) << endmsg;
3316 /* see if there an easy to find peakfile for this file, and remove it.
3319 string base = Glib::path_get_basename (*x);
3320 base += "%A"; /* this is what we add for the channel suffix of all native files,
3321 or for the first channel of embedded files. it will miss
3322 some peakfiles for other channels
3324 string peakpath = construct_peak_filepath (base);
3326 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3327 if (::g_unlink (peakpath.c_str ()) != 0) {
3328 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3329 g_strerror (errno)) << endmsg;
3330 /* try to back out */
3331 ::g_rename (newpath.c_str (), _path.c_str ());
3336 rep.paths.push_back (*x);
3337 rep.space += statbuf.st_size;
3340 /* dump the history list */
3344 /* save state so we don't end up a session file
3345 referring to non-existent sources.
3352 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3358 Session::cleanup_trash_sources (CleanupReport& rep)
3360 // FIXME: needs adaptation for MIDI
3362 vector<space_and_path>::iterator i;
3368 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3370 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3372 clear_directory (dead_dir, &rep.space, &rep.paths);
3379 Session::set_dirty ()
3381 /* never mark session dirty during loading */
3383 if (_state_of_the_state & Loading) {
3387 bool was_dirty = dirty();
3389 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3393 DirtyChanged(); /* EMIT SIGNAL */
3399 Session::set_clean ()
3401 bool was_dirty = dirty();
3403 _state_of_the_state = Clean;
3407 DirtyChanged(); /* EMIT SIGNAL */
3412 Session::set_deletion_in_progress ()
3414 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3418 Session::clear_deletion_in_progress ()
3420 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3424 Session::add_controllable (boost::shared_ptr<Controllable> c)
3426 /* this adds a controllable to the list managed by the Session.
3427 this is a subset of those managed by the Controllable class
3428 itself, and represents the only ones whose state will be saved
3429 as part of the session.
3432 Glib::Threads::Mutex::Lock lm (controllables_lock);
3433 controllables.insert (c);
3436 struct null_deleter { void operator()(void const *) const {} };
3439 Session::remove_controllable (Controllable* c)
3441 if (_state_of_the_state & Deletion) {
3445 Glib::Threads::Mutex::Lock lm (controllables_lock);
3447 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3449 if (x != controllables.end()) {
3450 controllables.erase (x);
3454 boost::shared_ptr<Controllable>
3455 Session::controllable_by_id (const PBD::ID& id)
3457 Glib::Threads::Mutex::Lock lm (controllables_lock);
3459 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3460 if ((*i)->id() == id) {
3465 return boost::shared_ptr<Controllable>();
3468 boost::shared_ptr<Controllable>
3469 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3471 boost::shared_ptr<Controllable> c;
3472 boost::shared_ptr<Stripable> s;
3473 boost::shared_ptr<Route> r;
3475 switch (desc.top_level_type()) {
3476 case ControllableDescriptor::NamedRoute:
3478 std::string str = desc.top_level_name();
3480 if (str == "Master" || str == "master") {
3482 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3484 } else if (str == "auditioner") {
3487 s = route_by_name (desc.top_level_name());
3493 case ControllableDescriptor::PresentationOrderRoute:
3494 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3497 case ControllableDescriptor::PresentationOrderTrack:
3498 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3501 case ControllableDescriptor::PresentationOrderBus:
3502 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3505 case ControllableDescriptor::PresentationOrderVCA:
3506 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3509 case ControllableDescriptor::SelectionCount:
3510 s = route_by_selected_count (desc.selection_id());
3518 r = boost::dynamic_pointer_cast<Route> (s);
3520 switch (desc.subtype()) {
3521 case ControllableDescriptor::Gain:
3522 c = s->gain_control ();
3525 case ControllableDescriptor::Trim:
3526 c = s->trim_control ();
3529 case ControllableDescriptor::Solo:
3530 c = s->solo_control();
3533 case ControllableDescriptor::Mute:
3534 c = s->mute_control();
3537 case ControllableDescriptor::Recenable:
3538 c = s->rec_enable_control ();
3541 case ControllableDescriptor::PanDirection:
3542 c = s->pan_azimuth_control();
3545 case ControllableDescriptor::PanWidth:
3546 c = s->pan_width_control();
3549 case ControllableDescriptor::PanElevation:
3550 c = s->pan_elevation_control();
3553 case ControllableDescriptor::Balance:
3554 /* XXX simple pan control */
3557 case ControllableDescriptor::PluginParameter:
3559 uint32_t plugin = desc.target (0);
3560 uint32_t parameter_index = desc.target (1);
3562 /* revert to zero based counting */
3568 if (parameter_index > 0) {
3576 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3579 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3580 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3585 case ControllableDescriptor::SendGain: {
3586 uint32_t send = desc.target (0);
3593 c = r->send_level_controllable (send);
3598 /* relax and return a null pointer */
3606 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3609 Stateful::add_instant_xml (node, _path);
3612 if (write_to_config) {
3613 Config->add_instant_xml (node);
3618 Session::instant_xml (const string& node_name)
3620 return Stateful::instant_xml (node_name, _path);
3624 Session::save_history (string snapshot_name)
3632 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3633 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3637 if (snapshot_name.empty()) {
3638 snapshot_name = _current_snapshot_name;
3641 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3642 const string backup_filename = history_filename + backup_suffix;
3643 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3644 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3646 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3647 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3648 error << _("could not backup old history file, current history not saved") << endmsg;
3653 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3655 if (!tree.write (xml_path))
3657 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3659 if (g_remove (xml_path.c_str()) != 0) {
3660 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3661 xml_path, g_strerror (errno)) << endmsg;
3663 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3664 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3665 backup_path, g_strerror (errno)) << endmsg;
3675 Session::restore_history (string snapshot_name)
3679 if (snapshot_name.empty()) {
3680 snapshot_name = _current_snapshot_name;
3683 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3684 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3686 info << "Loading history from " << xml_path << endmsg;
3688 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3689 info << string_compose (_("%1: no history file \"%2\" for this session."),
3690 _name, xml_path) << endmsg;
3694 if (!tree.read (xml_path)) {
3695 error << string_compose (_("Could not understand session history file \"%1\""),
3696 xml_path) << endmsg;
3703 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3706 UndoTransaction* ut = new UndoTransaction ();
3709 ut->set_name(t->property("name")->value());
3710 stringstream ss(t->property("tv-sec")->value());
3712 ss.str(t->property("tv-usec")->value());
3714 ut->set_timestamp(tv);
3716 for (XMLNodeConstIterator child_it = t->children().begin();
3717 child_it != t->children().end(); child_it++)
3719 XMLNode *n = *child_it;
3722 if (n->name() == "MementoCommand" ||
3723 n->name() == "MementoUndoCommand" ||
3724 n->name() == "MementoRedoCommand") {
3726 if ((c = memento_command_factory(n))) {
3730 } else if (n->name() == "NoteDiffCommand") {
3731 PBD::ID id (n->property("midi-source")->value());
3732 boost::shared_ptr<MidiSource> midi_source =
3733 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3735 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3737 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3740 } else if (n->name() == "SysExDiffCommand") {
3742 PBD::ID id (n->property("midi-source")->value());
3743 boost::shared_ptr<MidiSource> midi_source =
3744 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3746 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3748 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3751 } else if (n->name() == "PatchChangeDiffCommand") {
3753 PBD::ID id (n->property("midi-source")->value());
3754 boost::shared_ptr<MidiSource> midi_source =
3755 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3757 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3759 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3762 } else if (n->name() == "StatefulDiffCommand") {
3763 if ((c = stateful_diff_command_factory (n))) {
3764 ut->add_command (c);
3767 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3778 Session::config_changed (std::string p, bool ours)
3784 if (p == "seamless-loop") {
3786 } else if (p == "rf-speed") {
3788 } else if (p == "auto-loop") {
3790 } else if (p == "auto-input") {
3792 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3793 /* auto-input only makes a difference if we're rolling */
3794 set_track_monitor_input_status (!config.get_auto_input());
3797 } else if (p == "punch-in") {
3801 if ((location = _locations->auto_punch_location()) != 0) {
3803 if (config.get_punch_in ()) {
3804 replace_event (SessionEvent::PunchIn, location->start());
3806 remove_event (location->start(), SessionEvent::PunchIn);
3810 } else if (p == "punch-out") {
3814 if ((location = _locations->auto_punch_location()) != 0) {
3816 if (config.get_punch_out()) {
3817 replace_event (SessionEvent::PunchOut, location->end());
3819 clear_events (SessionEvent::PunchOut);
3823 } else if (p == "edit-mode") {
3825 Glib::Threads::Mutex::Lock lm (playlists->lock);
3827 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3828 (*i)->set_edit_mode (Config->get_edit_mode ());
3831 } else if (p == "use-video-sync") {
3833 waiting_for_sync_offset = config.get_use_video_sync();
3835 } else if (p == "mmc-control") {
3837 //poke_midi_thread ();
3839 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3841 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3843 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3845 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3847 } else if (p == "midi-control") {
3849 //poke_midi_thread ();
3851 } else if (p == "raid-path") {
3853 setup_raid_path (config.get_raid_path());
3855 } else if (p == "timecode-format") {
3859 } else if (p == "video-pullup") {
3863 } else if (p == "seamless-loop") {
3865 if (play_loop && transport_rolling()) {
3866 // to reset diskstreams etc
3867 request_play_loop (true);
3870 } else if (p == "rf-speed") {
3872 cumulative_rf_motion = 0;
3875 } else if (p == "click-sound") {
3877 setup_click_sounds (1);
3879 } else if (p == "click-emphasis-sound") {
3881 setup_click_sounds (-1);
3883 } else if (p == "clicking") {
3885 if (Config->get_clicking()) {
3886 if (_click_io && click_data) { // don't require emphasis data
3893 } else if (p == "click-gain") {
3896 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3899 } else if (p == "send-mtc") {
3901 if (Config->get_send_mtc ()) {
3902 /* mark us ready to send */
3903 next_quarter_frame_to_send = 0;
3906 } else if (p == "send-mmc") {
3908 _mmc->enable_send (Config->get_send_mmc ());
3910 } else if (p == "midi-feedback") {
3912 session_midi_feedback = Config->get_midi_feedback();
3914 } else if (p == "jack-time-master") {
3916 engine().reset_timebase ();
3918 } else if (p == "native-file-header-format") {
3920 if (!first_file_header_format_reset) {
3921 reset_native_file_format ();
3924 first_file_header_format_reset = false;
3926 } else if (p == "native-file-data-format") {
3928 if (!first_file_data_format_reset) {
3929 reset_native_file_format ();
3932 first_file_data_format_reset = false;
3934 } else if (p == "external-sync") {
3935 if (!config.get_external_sync()) {
3936 drop_sync_source ();
3938 switch_to_sync_source (Config->get_sync_source());
3940 } else if (p == "denormal-model") {
3942 } else if (p == "history-depth") {
3943 set_history_depth (Config->get_history_depth());
3944 } else if (p == "remote-model") {
3945 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3948 } else if (p == "initial-program-change") {
3950 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3953 buf[0] = MIDI::program; // channel zero by default
3954 buf[1] = (Config->get_initial_program_change() & 0x7f);
3956 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3958 } else if (p == "solo-mute-override") {
3959 // catch_up_on_solo_mute_override ();
3960 } else if (p == "listen-position" || p == "pfl-position") {
3961 listen_position_changed ();
3962 } else if (p == "solo-control-is-listen-control") {
3963 solo_control_mode_changed ();
3964 } else if (p == "solo-mute-gain") {
3965 _solo_cut_control->Changed (true, Controllable::NoGroup);
3966 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3967 last_timecode_valid = false;
3968 } else if (p == "playback-buffer-seconds") {
3969 AudioSource::allocate_working_buffers (frame_rate());
3970 } else if (p == "ltc-source-port") {
3971 reconnect_ltc_input ();
3972 } else if (p == "ltc-sink-port") {
3973 reconnect_ltc_output ();
3974 } else if (p == "timecode-generator-offset") {
3975 ltc_tx_parse_offset();
3976 } else if (p == "auto-return-target-list") {
3977 follow_playhead_priority ();
3984 Session::set_history_depth (uint32_t d)
3986 _history.set_depth (d);
3990 Session::load_diskstreams_2X (XMLNode const & node, int)
3993 XMLNodeConstIterator citer;
3995 clist = node.children();
3997 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4000 /* diskstreams added automatically by DiskstreamCreated handler */
4001 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4002 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4003 _diskstreams_2X.push_back (dsp);
4005 error << _("Session: unknown diskstream type in XML") << endmsg;
4009 catch (failed_constructor& err) {
4010 error << _("Session: could not load diskstream via XML state") << endmsg;
4018 /** Connect things to the MMC object */
4020 Session::setup_midi_machine_control ()
4022 _mmc = new MIDI::MachineControl;
4024 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4025 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4027 if (!async_out || !async_out) {
4031 /* XXXX argh, passing raw pointers back into libmidi++ */
4033 MIDI::Port* mmc_in = async_in.get();
4034 MIDI::Port* mmc_out = async_out.get();
4036 _mmc->set_ports (mmc_in, mmc_out);
4038 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4039 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4040 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4041 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4042 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4043 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4044 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4045 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4046 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4047 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4048 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4049 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4050 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4052 /* also handle MIDI SPP because its so common */
4054 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4055 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4056 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4059 boost::shared_ptr<Controllable>
4060 Session::solo_cut_control() const
4062 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4063 controls in Ardour that currently get presented to the user in the GUI that require
4064 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4066 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4067 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4071 return _solo_cut_control;
4075 Session::save_snapshot_name (const std::string & n)
4077 /* assure Stateful::_instant_xml is loaded
4078 * add_instant_xml() only adds to existing data and defaults
4079 * to use an empty Tree otherwise
4081 instant_xml ("LastUsedSnapshot");
4083 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4084 last_used_snapshot->add_property ("name", string(n));
4085 add_instant_xml (*last_used_snapshot, false);
4089 Session::set_snapshot_name (const std::string & n)
4091 _current_snapshot_name = n;
4092 save_snapshot_name (n);
4096 Session::rename (const std::string& new_name)
4098 string legal_name = legalize_for_path (new_name);
4104 string const old_sources_root = _session_dir->sources_root();
4106 if (!_writable || (_state_of_the_state & CannotSave)) {
4107 error << _("Cannot rename read-only session.") << endmsg;
4108 return 0; // don't show "messed up" warning
4110 if (record_status() == Recording) {
4111 error << _("Cannot rename session while recording") << endmsg;
4112 return 0; // don't show "messed up" warning
4115 StateProtector stp (this);
4120 * interchange subdirectory
4124 * Backup files are left unchanged and not renamed.
4127 /* Windows requires that we close all files before attempting the
4128 * rename. This works on other platforms, but isn't necessary there.
4129 * Leave it in place for all platforms though, since it may help
4130 * catch issues that could arise if the way Source files work ever
4131 * change (since most developers are not using Windows).
4134 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4135 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4141 /* pass one: not 100% safe check that the new directory names don't
4145 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4149 /* this is a stupid hack because Glib::path_get_dirname() is
4150 * lexical-only, and so passing it /a/b/c/ gives a different
4151 * result than passing it /a/b/c ...
4154 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4155 oldstr = oldstr.substr (0, oldstr.length() - 1);
4158 string base = Glib::path_get_dirname (oldstr);
4160 newstr = Glib::build_filename (base, legal_name);
4162 cerr << "Looking for " << newstr << endl;
4164 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4165 cerr << " exists\n";
4174 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4180 /* this is a stupid hack because Glib::path_get_dirname() is
4181 * lexical-only, and so passing it /a/b/c/ gives a different
4182 * result than passing it /a/b/c ...
4185 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4186 oldstr = oldstr.substr (0, oldstr.length() - 1);
4189 string base = Glib::path_get_dirname (oldstr);
4190 newstr = Glib::build_filename (base, legal_name);
4192 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4194 cerr << "Rename " << oldstr << " => " << newstr << endl;
4195 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4196 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4197 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4201 /* Reset path in "session dirs" */
4206 /* reset primary SessionDirectory object */
4209 (*_session_dir) = newstr;
4214 /* now rename directory below session_dir/interchange */
4216 string old_interchange_dir;
4217 string new_interchange_dir;
4219 /* use newstr here because we renamed the path
4220 * (folder/directory) that used to be oldstr to newstr above
4223 v.push_back (newstr);
4224 v.push_back (interchange_dir_name);
4225 v.push_back (Glib::path_get_basename (oldstr));
4227 old_interchange_dir = Glib::build_filename (v);
4230 v.push_back (newstr);
4231 v.push_back (interchange_dir_name);
4232 v.push_back (legal_name);
4234 new_interchange_dir = Glib::build_filename (v);
4236 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4238 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4239 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4240 old_interchange_dir, new_interchange_dir,
4243 error << string_compose (_("renaming %s as %2 failed (%3)"),
4244 old_interchange_dir, new_interchange_dir,
4253 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4254 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4256 cerr << "Rename " << oldstr << " => " << newstr << endl;
4258 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4259 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4260 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4266 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4268 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4269 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4271 cerr << "Rename " << oldstr << " => " << newstr << endl;
4273 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4274 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4275 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4280 /* remove old name from recent sessions */
4281 remove_recent_sessions (_path);
4284 /* update file source paths */
4286 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4287 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4289 string p = fs->path ();
4290 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4292 SourceFactory::setup_peakfile(i->second, true);
4296 set_snapshot_name (new_name);
4301 /* save state again to get everything just right */
4303 save_state (_current_snapshot_name);
4305 /* add to recent sessions */
4307 store_recent_sessions (new_name, _path);
4313 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4315 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4319 if (!tree.read (xmlpath)) {
4327 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4330 bool found_sr = false;
4331 bool found_data_format = false;
4333 if (get_session_info_from_path (tree, xmlpath)) {
4339 XMLProperty const * prop;
4340 XMLNode const * root (tree.root());
4342 if ((prop = root->property (X_("sample-rate"))) != 0) {
4343 sample_rate = atoi (prop->value());
4347 const XMLNodeList& children (root->children());
4348 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4349 const XMLNode* child = *c;
4350 if (child->name() == "Config") {
4351 const XMLNodeList& options (child->children());
4352 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4353 XMLNode const * option = *oc;
4354 XMLProperty const * name = option->property("name");
4360 if (name->value() == "native-file-data-format") {
4361 XMLProperty const * value = option->property ("value");
4363 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4365 found_data_format = true;
4371 if (found_data_format) {
4376 return !(found_sr && found_data_format); // zero if they are both found
4380 Session::get_snapshot_from_instant (const std::string& session_dir)
4382 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4384 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4389 if (!tree.read (instant_xml_path)) {
4393 XMLProperty const * prop;
4394 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4395 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4396 return prop->value();
4402 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4403 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4406 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4410 SourcePathMap source_path_map;
4412 boost::shared_ptr<AudioFileSource> afs;
4417 Glib::Threads::Mutex::Lock lm (source_lock);
4419 cerr << " total sources = " << sources.size();
4421 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4422 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4428 if (fs->within_session()) {
4432 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4433 source_path_map[fs->path()].push_back (fs);
4435 SeveralFileSources v;
4437 source_path_map.insert (make_pair (fs->path(), v));
4443 cerr << " fsources = " << total << endl;
4445 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4447 /* tell caller where we are */
4449 string old_path = i->first;
4451 callback (n, total, old_path);
4453 cerr << old_path << endl;
4457 switch (i->second.front()->type()) {
4458 case DataType::AUDIO:
4459 new_path = new_audio_source_path_for_embedded (old_path);
4462 case DataType::MIDI:
4463 /* XXX not implemented yet */
4467 if (new_path.empty()) {
4471 cerr << "Move " << old_path << " => " << new_path << endl;
4473 if (!copy_file (old_path, new_path)) {
4474 cerr << "failed !\n";
4478 /* make sure we stop looking in the external
4479 dir/folder. Remember, this is an all-or-nothing
4480 operations, it doesn't merge just some files.
4482 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4484 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4485 (*f)->set_path (new_path);
4490 save_state ("", false, false);
4496 bool accept_all_files (string const &, void *)
4502 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4504 /* 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.
4509 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4511 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4513 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4515 v.push_back (new_session_folder); /* full path */
4516 v.push_back (interchange_dir_name);
4517 v.push_back (new_session_path); /* just one directory/folder */
4518 v.push_back (typedir);
4519 v.push_back (Glib::path_get_basename (old_path));
4521 return Glib::build_filename (v);
4525 Session::save_as (SaveAs& saveas)
4527 vector<string> files;
4528 string current_folder = Glib::path_get_dirname (_path);
4529 string new_folder = legalize_for_path (saveas.new_name);
4530 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4531 int64_t total_bytes = 0;
4535 int32_t internal_file_cnt = 0;
4537 vector<string> do_not_copy_extensions;
4538 do_not_copy_extensions.push_back (statefile_suffix);
4539 do_not_copy_extensions.push_back (pending_suffix);
4540 do_not_copy_extensions.push_back (backup_suffix);
4541 do_not_copy_extensions.push_back (temp_suffix);
4542 do_not_copy_extensions.push_back (history_suffix);
4544 /* get total size */
4546 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4548 /* need to clear this because
4549 * find_files_matching_filter() is cumulative
4554 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4556 all += files.size();
4558 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4560 g_stat ((*i).c_str(), &gsb);
4561 total_bytes += gsb.st_size;
4565 /* save old values so we can switch back if we are not switching to the new session */
4567 string old_path = _path;
4568 string old_name = _name;
4569 string old_snapshot = _current_snapshot_name;
4570 string old_sd = _session_dir->root_path();
4571 vector<string> old_search_path[DataType::num_types];
4572 string old_config_search_path[DataType::num_types];
4574 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4575 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4576 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4577 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4579 /* switch session directory */
4581 (*_session_dir) = to_dir;
4583 /* create new tree */
4585 if (!_session_dir->create()) {
4586 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4591 /* copy all relevant files. Find each location in session_dirs,
4592 * and copy files from there to target.
4595 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4597 /* need to clear this because
4598 * find_files_matching_filter() is cumulative
4603 const size_t prefix_len = (*sd).path.size();
4605 /* Work just on the files within this session dir */
4607 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4609 /* add dir separator to protect against collisions with
4610 * track names (e.g. track named "audiofiles" or
4614 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4615 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4616 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4618 /* copy all the files. Handling is different for media files
4619 than others because of the *silly* subtree we have below the interchange
4620 folder. That really was a bad idea, but I'm not fixing it as part of
4621 implementing ::save_as().
4624 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4626 std::string from = *i;
4629 string filename = Glib::path_get_basename (from);
4630 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4631 if (filename == ".DS_STORE") {
4636 if (from.find (audiofile_dir_string) != string::npos) {
4638 /* audio file: only copy if asked */
4640 if (saveas.include_media && saveas.copy_media) {
4642 string to = make_new_media_path (*i, to_dir, new_folder);
4644 info << "media file copying from " << from << " to " << to << endmsg;
4646 if (!copy_file (from, to)) {
4647 throw Glib::FileError (Glib::FileError::IO_ERROR,
4648 string_compose(_("\ncopying \"%1\" failed !"), from));
4652 /* we found media files inside the session folder */
4654 internal_file_cnt++;
4656 } else if (from.find (midifile_dir_string) != string::npos) {
4658 /* midi file: always copy unless
4659 * creating an empty new session
4662 if (saveas.include_media) {
4664 string to = make_new_media_path (*i, to_dir, new_folder);
4666 info << "media file copying from " << from << " to " << to << endmsg;
4668 if (!copy_file (from, to)) {
4669 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4673 /* we found media files inside the session folder */
4675 internal_file_cnt++;
4677 } else if (from.find (analysis_dir_string) != string::npos) {
4679 /* make sure analysis dir exists in
4680 * new session folder, but we're not
4681 * copying analysis files here, see
4685 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4690 /* normal non-media file. Don't copy state, history, etc.
4693 bool do_copy = true;
4695 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4696 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4697 /* end of filename matches extension, do not copy file */
4703 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4704 /* don't copy peakfiles if
4705 * we're not copying media
4711 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4713 info << "attempting to make directory/folder " << to << endmsg;
4715 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4716 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4719 info << "attempting to copy " << from << " to " << to << endmsg;
4721 if (!copy_file (from, to)) {
4722 throw Glib::FileError (Glib::FileError::IO_ERROR,
4723 string_compose(_("\ncopying \"%1\" failed !"), from));
4728 /* measure file size even if we're not going to copy so that our Progress
4729 signals are correct, since we included these do-not-copy files
4730 in the computation of the total size and file count.
4734 g_stat (from.c_str(), &gsb);
4735 copied += gsb.st_size;
4738 double fraction = (double) copied / total_bytes;
4740 bool keep_going = true;
4742 if (saveas.copy_media) {
4744 /* no need or expectation of this if
4745 * media is not being copied, because
4746 * it will be fast(ish).
4749 /* tell someone "X percent, file M of N"; M is one-based */
4751 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4759 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4765 /* copy optional folders, if any */
4767 string old = plugins_dir ();
4768 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4769 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4770 copy_files (old, newdir);
4773 old = externals_dir ();
4774 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4775 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4776 copy_files (old, newdir);
4779 old = automation_dir ();
4780 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4781 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4782 copy_files (old, newdir);
4785 if (saveas.include_media) {
4787 if (saveas.copy_media) {
4788 #ifndef PLATFORM_WINDOWS
4789 /* There are problems with analysis files on
4790 * Windows, because they used a colon in their
4791 * names as late as 4.0. Colons are not legal
4792 * under Windows even if NTFS allows them.
4794 * This is a tricky problem to solve so for
4795 * just don't copy these files. They will be
4796 * regenerated as-needed anyway, subject to the
4797 * existing issue that the filenames will be
4798 * rejected by Windows, which is a separate
4799 * problem (though related).
4802 /* only needed if we are copying media, since the
4803 * analysis data refers to media data
4806 old = analysis_dir ();
4807 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4808 string newdir = Glib::build_filename (to_dir, "analysis");
4809 copy_files (old, newdir);
4811 #endif /* PLATFORM_WINDOWS */
4817 set_snapshot_name (saveas.new_name);
4818 _name = saveas.new_name;
4820 if (saveas.include_media && !saveas.copy_media) {
4822 /* reset search paths of the new session (which we're pretending to be right now) to
4823 include the original session search path, so we can still find all audio.
4826 if (internal_file_cnt) {
4827 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4828 ensure_search_path_includes (*s, DataType::AUDIO);
4829 cerr << "be sure to include " << *s << " for audio" << endl;
4832 /* we do not do this for MIDI because we copy
4833 all MIDI files if saveas.include_media is
4839 bool was_dirty = dirty ();
4841 save_state ("", false, false, !saveas.include_media);
4842 save_default_options ();
4844 if (saveas.copy_media && saveas.copy_external) {
4845 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4846 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4850 saveas.final_session_folder_name = _path;
4852 store_recent_sessions (_name, _path);
4854 if (!saveas.switch_to) {
4856 /* switch back to the way things were */
4860 set_snapshot_name (old_snapshot);
4862 (*_session_dir) = old_sd;
4868 if (internal_file_cnt) {
4869 /* reset these to their original values */
4870 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4871 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4876 /* prune session dirs, and update disk space statistics
4881 session_dirs.clear ();
4882 session_dirs.push_back (sp);
4883 refresh_disk_space ();
4885 /* ensure that all existing tracks reset their current capture source paths
4887 reset_write_sources (true, true);
4889 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4890 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4893 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4894 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4900 if (fs->within_session()) {
4901 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4902 fs->set_path (newpath);
4907 } catch (Glib::FileError& e) {
4909 saveas.failure_message = e.what();
4911 /* recursively remove all the directories */
4913 remove_directory (to_dir);
4921 saveas.failure_message = _("unknown reason");
4923 /* recursively remove all the directories */
4925 remove_directory (to_dir);
4935 static void set_progress (Progress* p, size_t n, size_t t)
4937 p->set_progress (float (n) / float(t));
4941 Session::archive_session (const std::string& dest, const std::string& name, ArchiveEncode compress_audio, Progress* progress)
4943 if (dest.empty () || name.empty ()) {
4947 /* save current values */
4948 bool was_dirty = dirty ();
4949 string old_path = _path;
4950 string old_name = _name;
4951 string old_snapshot = _current_snapshot_name;
4952 string old_sd = _session_dir->root_path();
4953 string old_config_search_path[DataType::num_types];
4954 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4955 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4957 /* ensure that session-path is included in search-path */
4959 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4960 if ((*sd).path == old_path) {
4968 /* create temporary dir to save session to */
4969 #ifdef PLATFORM_WINDOWS
4970 char tmp[256] = "C:\\TEMP\\";
4971 GetTempPath (sizeof (tmp), tmp);
4973 char const* tmp = getenv("TMPDIR");
4978 if ((strlen (tmp) + 21) > 1024) {
4983 strcpy (tmptpl, tmp);
4984 strcat (tmptpl, "ardourarchive-XXXXXX");
4985 char* tmpdir = g_mkdtemp (tmptpl);
4991 std::string to_dir = std::string (tmpdir);
4993 /* switch session directory temporarily */
4994 (*_session_dir) = to_dir;
4996 if (!_session_dir->create()) {
4997 (*_session_dir) = old_sd;
4998 remove_directory (to_dir);
5002 /* prepare archive */
5003 string archive = Glib::build_filename (dest, name + ".tar.xz");
5006 cout << "ARCHIVE: " << archive << "\n";
5009 PBD::ScopedConnectionList progress_connection;
5010 PBD::FileArchive ar (archive);
5012 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5015 /* collect files to archive */
5016 std::map<string,string> filemap;
5018 vector<string> do_not_copy_extensions;
5019 do_not_copy_extensions.push_back (statefile_suffix);
5020 do_not_copy_extensions.push_back (pending_suffix);
5021 do_not_copy_extensions.push_back (backup_suffix);
5022 do_not_copy_extensions.push_back (temp_suffix);
5023 do_not_copy_extensions.push_back (history_suffix);
5025 vector<string> blacklist_dirs;
5026 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5027 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5028 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5029 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5030 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5031 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5033 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5035 if (compress_audio != NO_ENCODE) {
5036 Glib::Threads::Mutex::Lock lm (source_lock);
5037 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5038 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5042 if (afs->readable_length () == 0) {
5046 orig_sources[afs] = afs->path();
5048 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5049 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5050 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5052 // TODO: set progress to "encoding", use total readable_length () somehow.
5053 // .. or a custom progress report like save-as.
5055 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, NULL /*progress*/);
5056 afs->replace_file (new_path);
5059 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5064 /* index files relevant for this session */
5065 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5066 vector<string> files;
5068 size_t prefix_len = (*sd).path.size();
5069 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5073 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5075 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5076 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5077 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5079 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5080 std::string from = *i;
5083 string filename = Glib::path_get_basename (from);
5084 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5085 if (filename == ".DS_STORE") {
5090 if (from.find (audiofile_dir_string) != string::npos) {
5091 if (!compress_audio != NO_ENCODE) {
5092 filemap[from] = make_new_media_path (from, name, name);
5094 } else if (from.find (midifile_dir_string) != string::npos) {
5095 filemap[from] = make_new_media_path (from, name, name);
5096 } else if (from.find (videofile_dir_string) != string::npos) {
5097 filemap[from] = make_new_media_path (from, name, name);
5099 bool do_copy = true;
5100 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5101 if (from.find (*v) != string::npos) {
5106 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5107 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5114 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5120 /* include external media */
5122 Glib::Threads::Mutex::Lock lm (source_lock);
5123 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5124 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5128 if (fs->within_session()) {
5132 if (fs->type () != DataType::AUDIO) {
5136 std::string from = fs->path();
5137 filemap[from] = make_new_media_path (from, name, name);
5138 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5142 /* write session file */
5144 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5146 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5148 save_default_options ();
5150 size_t prefix_len = _path.size();
5151 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5155 /* collect session-state files */
5156 vector<string> files;
5157 do_not_copy_extensions.clear ();
5158 do_not_copy_extensions.push_back (history_suffix);
5160 blacklist_dirs.clear ();
5161 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5163 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5164 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5165 std::string from = *i;
5166 bool do_copy = true;
5167 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5168 if (from.find (*v) != string::npos) {
5173 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5174 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5180 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5184 /* restore original values */
5187 set_snapshot_name (old_snapshot);
5188 (*_session_dir) = old_sd;
5192 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5193 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5195 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5196 i->first->replace_file (i->second);
5200 /* done -- now zip */
5201 for (std::map<string,string>::const_iterator i = filemap.begin(); i != filemap.end (); ++i) {
5202 cout << "archive " << (*i).first << " as " << (*i).second << "\n";
5206 int rv = ar.create (filemap);
5207 remove_directory (to_dir);
5213 Session::undo (uint32_t n)
5215 if (actively_recording()) {
5223 Session::redo (uint32_t n)
5225 if (actively_recording()) {