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"
31 #include <cstdio> /* snprintf(3) ... grrr */
44 #include <sys/param.h>
45 #include <sys/mount.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
53 #include <glib/gstdio.h>
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/boost_debug.h"
67 #include "pbd/basename.h"
68 #include "pbd/controllable_descriptor.h"
69 #include "pbd/debug.h"
70 #include "pbd/enumwriter.h"
71 #include "pbd/error.h"
72 #include "pbd/file_utils.h"
73 #include "pbd/pathexpand.h"
74 #include "pbd/pthread_utils.h"
75 #include "pbd/stacktrace.h"
76 #include "pbd/convert.h"
77 #include "pbd/localtime_r.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_diskstream.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/butler.h"
88 #include "ardour/control_protocol_manager.h"
89 #include "ardour/directory_names.h"
90 #include "ardour/filename_extensions.h"
91 #include "ardour/graph.h"
92 #include "ardour/location.h"
93 #include "ardour/midi_model.h"
94 #include "ardour/midi_patch_manager.h"
95 #include "ardour/midi_region.h"
96 #include "ardour/midi_scene_changer.h"
97 #include "ardour/midi_source.h"
98 #include "ardour/midi_track.h"
99 #include "ardour/pannable.h"
100 #include "ardour/playlist_factory.h"
101 #include "ardour/playlist_source.h"
102 #include "ardour/port.h"
103 #include "ardour/processor.h"
104 #include "ardour/profile.h"
105 #include "ardour/proxy_controllable.h"
106 #include "ardour/recent_sessions.h"
107 #include "ardour/region_factory.h"
108 #include "ardour/route_group.h"
109 #include "ardour/send.h"
110 #include "ardour/session.h"
111 #include "ardour/session_directory.h"
112 #include "ardour/session_metadata.h"
113 #include "ardour/session_playlists.h"
114 #include "ardour/session_state_utils.h"
115 #include "ardour/silentfilesource.h"
116 #include "ardour/sndfilesource.h"
117 #include "ardour/source_factory.h"
118 #include "ardour/speakers.h"
119 #include "ardour/template_utils.h"
120 #include "ardour/tempo.h"
121 #include "ardour/ticker.h"
122 #include "ardour/user_bundle.h"
124 #include "control_protocol/control_protocol.h"
130 using namespace ARDOUR;
133 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
136 Session::pre_engine_init (string fullpath)
138 if (fullpath.empty()) {
140 throw failed_constructor();
143 /* discover canonical fullpath */
145 _path = canonical_path(fullpath);
148 if (Profile->get_trx() ) {
149 // Waves TracksLive has a usecase of session replacement with a new one.
150 // We should check session state file (<session_name>.ardour) existance
151 // to determine if the session is new or not
153 string full_session_name = Glib::build_filename( fullpath, _name );
154 full_session_name += statefile_suffix;
156 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
158 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
161 /* finish initialization that can't be done in a normal C++ constructor
165 timerclear (&last_mmc_step);
166 g_atomic_int_set (&processing_prohibited, 0);
167 g_atomic_int_set (&_record_status, Disabled);
168 g_atomic_int_set (&_playback_load, 100);
169 g_atomic_int_set (&_capture_load, 100);
171 _all_route_group->set_active (true, this);
172 interpolation.add_channel_to (0, 0);
174 if (config.get_use_video_sync()) {
175 waiting_for_sync_offset = true;
177 waiting_for_sync_offset = false;
180 last_rr_session_dir = session_dirs.begin();
182 set_history_depth (Config->get_history_depth());
184 /* default: assume simple stereo speaker configuration */
186 _speakers->setup_default_speakers (2);
188 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
189 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
190 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
191 add_controllable (_solo_cut_control);
193 /* These are all static "per-class" signals */
195 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
196 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
197 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
198 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
199 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
201 /* stop IO objects from doing stuff until we're ready for them */
203 Delivery::disable_panners ();
204 IO::disable_connecting ();
208 Session::post_engine_init ()
210 BootMessage (_("Set block size and sample rate"));
212 set_block_size (_engine.samples_per_cycle());
213 set_frame_rate (_engine.sample_rate());
215 BootMessage (_("Using configuration"));
217 _midi_ports = new MidiPortManager;
219 MIDISceneChanger* msc;
221 _scene_changer = msc = new MIDISceneChanger (*this);
222 msc->set_input_port (scene_input_port());
223 msc->set_output_port (scene_out());
225 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
226 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
228 setup_midi_machine_control ();
230 if (_butler->start_thread()) {
234 if (start_midi_thread ()) {
238 setup_click_sounds (0);
239 setup_midi_control ();
241 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
242 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
245 /* tempo map requires sample rate knowledge */
248 _tempo_map = new TempoMap (_current_frame_rate);
249 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
251 /* MidiClock requires a tempo map */
253 midi_clock = new MidiClockTicker ();
254 midi_clock->set_session (this);
256 /* crossfades require sample rate knowledge */
258 SndFileSource::setup_standard_crossfades (*this, frame_rate());
259 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
261 AudioDiskstream::allocate_working_buffers();
262 refresh_disk_space ();
264 /* we're finally ready to call set_state() ... all objects have
265 * been created, the engine is running.
269 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
273 // set_state() will call setup_raid_path(), but if it's a new session we need
274 // to call setup_raid_path() here.
275 setup_raid_path (_path);
280 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
281 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
283 Config->map_parameters (ff);
284 config.map_parameters (ft);
285 _butler->map_parameters ();
287 /* Reset all panners */
289 Delivery::reset_panners ();
291 /* this will cause the CPM to instantiate any protocols that are in use
292 * (or mandatory), which will pass it this Session, and then call
293 * set_state() on each instantiated protocol to match stored state.
296 ControlProtocolManager::instance().set_session (this);
298 /* This must be done after the ControlProtocolManager set_session above,
299 as it will set states for ports which the ControlProtocolManager creates.
302 // XXX set state of MIDI::Port's
303 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
305 /* And this must be done after the MIDI::Manager::set_port_states as
306 * it will try to make connections whose details are loaded by set_port_states.
311 /* Let control protocols know that we are now all connected, so they
312 * could start talking to surfaces if they want to.
315 ControlProtocolManager::instance().midi_connectivity_established ();
317 if (_is_new && !no_auto_connect()) {
318 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
319 auto_connect_master_bus ();
322 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
324 /* update latencies */
326 initialize_latencies ();
328 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
329 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
330 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
332 } catch (AudioEngine::PortRegistrationFailure& err) {
333 /* handle this one in a different way than all others, so that its clear what happened */
334 error << err.what() << endmsg;
340 BootMessage (_("Reset Remote Controls"));
342 // send_full_time_code (0);
343 _engine.transport_locate (0);
345 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
346 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
348 MIDI::Name::MidiPatchManager::instance().set_session (this);
351 /* initial program change will be delivered later; see ::config_changed() */
353 _state_of_the_state = Clean;
355 Port::set_connecting_blocked (false);
357 DirtyChanged (); /* EMIT SIGNAL */
361 } else if (state_was_pending) {
363 remove_pending_capture_state ();
364 state_was_pending = false;
367 /* Now, finally, we can fill the playback buffers */
369 BootMessage (_("Filling playback buffers"));
371 boost::shared_ptr<RouteList> rl = routes.reader();
372 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
373 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
374 if (trk && !trk->hidden()) {
375 trk->seek (_transport_frame, true);
383 Session::session_loaded ()
387 _state_of_the_state = Clean;
389 DirtyChanged (); /* EMIT SIGNAL */
393 } else if (state_was_pending) {
395 remove_pending_capture_state ();
396 state_was_pending = false;
399 /* Now, finally, we can fill the playback buffers */
401 BootMessage (_("Filling playback buffers"));
402 force_locate (_transport_frame, false);
406 Session::raid_path () const
408 Searchpath raid_search_path;
410 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
411 raid_search_path += (*i).path;
414 return raid_search_path.to_string ();
418 Session::setup_raid_path (string path)
427 session_dirs.clear ();
429 Searchpath search_path(path);
430 Searchpath sound_search_path;
431 Searchpath midi_search_path;
433 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
435 sp.blocks = 0; // not needed
436 session_dirs.push_back (sp);
438 SessionDirectory sdir(sp.path);
440 sound_search_path += sdir.sound_path ();
441 midi_search_path += sdir.midi_path ();
444 // reset the round-robin soundfile path thingie
445 last_rr_session_dir = session_dirs.begin();
449 Session::path_is_within_session (const std::string& path)
451 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
452 if (PBD::path_is_within (i->path, path)) {
460 Session::ensure_subdirs ()
464 dir = session_directory().peak_path();
466 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
467 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
471 dir = session_directory().sound_path();
473 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
474 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
478 dir = session_directory().midi_path();
480 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
481 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
485 dir = session_directory().dead_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().export_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = analysis_dir ();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = plugins_dir ();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = externals_dir ();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
523 /** @param session_template directory containing session template, or empty.
524 * Caller must not hold process lock.
527 Session::create (const string& session_template, BusProfile* bus_profile)
529 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
534 if (ensure_subdirs ()) {
538 _writable = exists_and_writable (_path);
540 if (!session_template.empty()) {
541 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
543 FILE* in = g_fopen (in_path.c_str(), "rb");
546 /* no need to call legalize_for_path() since the string
547 * in session_template is already a legal path name
549 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
551 FILE* out = g_fopen (out_path.c_str(), "wb");
555 stringstream new_session;
558 size_t charsRead = fread (buf, sizeof(char), 1024, in);
561 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
566 if (charsRead == 0) {
569 new_session.write (buf, charsRead);
573 string file_contents = new_session.str();
574 size_t writeSize = file_contents.length();
575 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
576 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
584 if (!ARDOUR::Profile->get_trx()) {
585 /* Copy plugin state files from template to new session */
586 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
587 copy_recurse (template_plugins, plugins_dir ());
593 error << string_compose (_("Could not open %1 for writing session template"), out_path)
600 error << string_compose (_("Could not open session template %1 for reading"), in_path)
607 if (Profile->get_trx()) {
609 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
610 Remember that this is a brand new session. Sessions
611 loaded from saved state will get this range from the saved state.
614 set_session_range_location (0, 0);
616 /* Initial loop location, from absolute zero, length 10 seconds */
618 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
619 _locations->add (loc, true);
620 set_auto_loop_location (loc);
623 _state_of_the_state = Clean;
625 /* set up Master Out and Control Out if necessary */
630 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
632 // Waves Tracks: always create master bus for Tracks
633 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
634 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
638 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
639 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
642 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
643 r->input()->ensure_io (count, false, this);
644 r->output()->ensure_io (count, false, this);
650 /* prohibit auto-connect to master, because there isn't one */
651 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
655 add_routes (rl, false, false, false);
658 // Waves Tracks: Skip this. Always use autoconnection for Tracks
659 if (!ARDOUR::Profile->get_trx()) {
661 /* this allows the user to override settings with an environment variable.
664 if (no_auto_connect()) {
665 bus_profile->input_ac = AutoConnectOption (0);
666 bus_profile->output_ac = AutoConnectOption (0);
669 Config->set_input_auto_connect (bus_profile->input_ac);
670 Config->set_output_auto_connect (bus_profile->output_ac);
674 if (Config->get_use_monitor_bus() && bus_profile) {
675 add_monitor_section ();
682 Session::maybe_write_autosave()
684 if (dirty() && record_status() != Recording) {
685 save_state("", true);
690 Session::remove_pending_capture_state ()
692 std::string pending_state_file_path(_session_dir->root_path());
694 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
698 if (g_remove (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 /** Rename a state file.
705 * @param old_name Old snapshot name.
706 * @param new_name New snapshot name.
709 Session::rename_state (string old_name, string new_name)
711 if (old_name == _current_snapshot_name || old_name == _name) {
712 /* refuse to rename the current snapshot or the "main" one */
716 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
717 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
719 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
720 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
722 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
723 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
724 old_name, new_name, g_strerror(errno)) << endmsg;
728 /** Remove a state file.
729 * @param snapshot_name Snapshot name.
732 Session::remove_state (string snapshot_name)
734 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
735 // refuse to remove the current snapshot or the "main" one
739 std::string xml_path(_session_dir->root_path());
741 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
743 if (!create_backup_file (xml_path)) {
744 // don't remove it if a backup can't be made
745 // create_backup_file will log the error.
750 if (g_remove (xml_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
752 xml_path, g_strerror (errno)) << endmsg;
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
761 std::string xml_path(_session_dir->root_path());
763 /* prevent concurrent saves from different threads */
765 Glib::Threads::Mutex::Lock lm (save_state_lock);
767 if (!_writable || (_state_of_the_state & CannotSave)) {
771 if (g_atomic_int_get(&_suspend_save)) {
775 _save_queued = false;
777 if (!_engine.connected ()) {
778 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
784 /* tell sources we're saving first, in case they write out to a new file
785 * which should be saved with the state rather than the old one */
786 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
788 i->second->session_saved();
789 } catch (Evoral::SMF::FileError& e) {
790 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
794 SessionSaveUnderway (); /* EMIT SIGNAL */
797 tree.set_root (&get_template());
799 tree.set_root (&get_state());
802 if (snapshot_name.empty()) {
803 snapshot_name = _current_snapshot_name;
804 } else if (switch_to_snapshot) {
805 _current_snapshot_name = snapshot_name;
810 /* proper save: use statefile_suffix (.ardour in English) */
812 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
814 /* make a backup copy of the old file */
816 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
817 // create_backup_file will log the error
823 /* pending save: use pending_suffix (.pending in English) */
824 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
827 std::string tmp_path(_session_dir->root_path());
828 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
830 cerr << "actually writing state to " << tmp_path << endl;
832 if (!tree.write (tmp_path)) {
833 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
834 if (g_remove (tmp_path.c_str()) != 0) {
835 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
836 tmp_path, g_strerror (errno)) << endmsg;
842 cerr << "renaming state to " << xml_path << endl;
844 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
845 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
846 tmp_path, xml_path, g_strerror(errno)) << endmsg;
847 if (g_remove (tmp_path.c_str()) != 0) {
848 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
849 tmp_path, g_strerror (errno)) << endmsg;
857 save_history (snapshot_name);
859 bool was_dirty = dirty();
861 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
864 DirtyChanged (); /* EMIT SIGNAL */
867 StateSaved (snapshot_name); /* EMIT SIGNAL */
874 Session::restore_state (string snapshot_name)
876 if (load_state (snapshot_name) == 0) {
877 set_state (*state_tree->root(), Stateful::loading_state_version);
884 Session::load_state (string snapshot_name)
889 state_was_pending = false;
891 /* check for leftover pending state from a crashed capture attempt */
893 std::string xmlpath(_session_dir->root_path());
894 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
896 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
898 /* there is pending state from a crashed capture attempt */
900 boost::optional<int> r = AskAboutPendingState();
901 if (r.get_value_or (1)) {
902 state_was_pending = true;
906 if (!state_was_pending) {
907 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
910 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
911 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
912 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
913 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
918 state_tree = new XMLTree;
922 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
924 if (!state_tree->read (xmlpath)) {
925 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
931 XMLNode& root (*state_tree->root());
933 if (root.name() != X_("Session")) {
934 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
940 const XMLProperty* prop;
942 if ((prop = root.property ("version")) == 0) {
943 /* no version implies very old version of Ardour */
944 Stateful::loading_state_version = 1000;
946 if (prop->value().find ('.') != string::npos) {
947 /* old school version format */
948 if (prop->value()[0] == '2') {
949 Stateful::loading_state_version = 2000;
951 Stateful::loading_state_version = 3000;
954 Stateful::loading_state_version = atoi (prop->value());
958 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
960 std::string backup_path(_session_dir->root_path());
961 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
962 backup_path = Glib::build_filename (backup_path, backup_filename);
964 // only create a backup for a given statefile version once
966 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
968 VersionMismatch (xmlpath, backup_path);
970 if (!copy_file (xmlpath, backup_path)) {;
980 Session::load_options (const XMLNode& node)
982 LocaleGuard lg (X_("C"));
983 config.set_variables (node);
988 Session::save_default_options ()
990 return config.save_state();
1000 Session::get_template()
1002 /* if we don't disable rec-enable, diskstreams
1003 will believe they need to store their capture
1004 sources in their state node.
1007 disable_record (false);
1009 return state(false);
1013 Session::state (bool full_state)
1015 XMLNode* node = new XMLNode("Session");
1019 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1020 node->add_property("version", buf);
1022 /* store configuration settings */
1026 node->add_property ("name", _name);
1027 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1028 node->add_property ("sample-rate", buf);
1030 if (session_dirs.size() > 1) {
1034 vector<space_and_path>::iterator i = session_dirs.begin();
1035 vector<space_and_path>::iterator next;
1037 ++i; /* skip the first one */
1041 while (i != session_dirs.end()) {
1045 if (next != session_dirs.end()) {
1046 p += G_SEARCHPATH_SEPARATOR;
1055 child = node->add_child ("Path");
1056 child->add_content (p);
1060 /* save the ID counter */
1062 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1063 node->add_property ("id-counter", buf);
1065 /* save the event ID counter */
1067 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1068 node->add_property ("event-counter", buf);
1070 /* various options */
1072 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1073 if (!midi_port_nodes.empty()) {
1074 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1075 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1076 midi_port_stuff->add_child_nocopy (**n);
1078 node->add_child_nocopy (*midi_port_stuff);
1081 node->add_child_nocopy (config.get_variables ());
1083 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1085 child = node->add_child ("Sources");
1088 Glib::Threads::Mutex::Lock sl (source_lock);
1090 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1092 /* Don't save information about non-file Sources, or
1093 * about non-destructive file sources that are empty
1094 * and unused by any regions.
1097 boost::shared_ptr<FileSource> fs;
1099 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1101 if (!fs->destructive()) {
1102 if (fs->empty() && !fs->used()) {
1107 child->add_child_nocopy (siter->second->get_state());
1112 child = node->add_child ("Regions");
1115 Glib::Threads::Mutex::Lock rl (region_lock);
1116 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1117 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1118 boost::shared_ptr<Region> r = i->second;
1119 /* only store regions not attached to playlists */
1120 if (r->playlist() == 0) {
1121 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1122 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1124 child->add_child_nocopy (r->get_state ());
1129 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1131 if (!cassocs.empty()) {
1132 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1134 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1136 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1137 i->first->id().print (buf, sizeof (buf));
1138 can->add_property (X_("copy"), buf);
1139 i->second->id().print (buf, sizeof (buf));
1140 can->add_property (X_("original"), buf);
1141 ca->add_child_nocopy (*can);
1151 node->add_child_nocopy (_locations->get_state());
1154 Locations loc (*this);
1155 // for a template, just create a new Locations, populate it
1156 // with the default start and end, and get the state for that.
1157 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1158 range->set (max_framepos, 0);
1160 XMLNode& locations_state = loc.get_state();
1162 if (ARDOUR::Profile->get_trx() && _locations) {
1163 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1164 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1165 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1166 locations_state.add_child_nocopy ((*i)->get_state ());
1170 node->add_child_nocopy (locations_state);
1173 child = node->add_child ("Bundles");
1175 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1176 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1177 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1179 child->add_child_nocopy (b->get_state());
1184 child = node->add_child ("Routes");
1186 boost::shared_ptr<RouteList> r = routes.reader ();
1188 RoutePublicOrderSorter cmp;
1189 RouteList public_order (*r);
1190 public_order.sort (cmp);
1192 /* the sort should have put control outs first */
1195 assert (_monitor_out == public_order.front());
1198 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1199 if (!(*i)->is_auditioner()) {
1201 child->add_child_nocopy ((*i)->get_state());
1203 child->add_child_nocopy ((*i)->get_template());
1209 playlists->add_state (node, full_state);
1211 child = node->add_child ("RouteGroups");
1212 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1213 child->add_child_nocopy ((*i)->get_state());
1217 XMLNode* gain_child = node->add_child ("Click");
1218 gain_child->add_child_nocopy (_click_io->state (full_state));
1219 gain_child->add_child_nocopy (_click_gain->state (full_state));
1223 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1224 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1228 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1229 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1232 node->add_child_nocopy (_speakers->get_state());
1233 node->add_child_nocopy (_tempo_map->get_state());
1234 node->add_child_nocopy (get_control_protocol_state());
1237 node->add_child_copy (*_extra_xml);
1244 Session::get_control_protocol_state ()
1246 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1247 return cpm.get_state();
1251 Session::set_state (const XMLNode& node, int version)
1255 const XMLProperty* prop;
1258 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1260 if (node.name() != X_("Session")) {
1261 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1265 if ((prop = node.property ("name")) != 0) {
1266 _name = prop->value ();
1269 if ((prop = node.property (X_("sample-rate"))) != 0) {
1271 _nominal_frame_rate = atoi (prop->value());
1273 if (_nominal_frame_rate != _current_frame_rate) {
1274 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1275 if (r.get_value_or (0)) {
1281 setup_raid_path(_session_dir->root_path());
1283 if ((prop = node.property (X_("id-counter"))) != 0) {
1285 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1286 ID::init_counter (x);
1288 /* old sessions used a timebased counter, so fake
1289 the startup ID counter based on a standard
1294 ID::init_counter (now);
1297 if ((prop = node.property (X_("event-counter"))) != 0) {
1298 Evoral::init_event_id_counter (atoi (prop->value()));
1302 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1303 _midi_ports->set_midi_port_states (child->children());
1306 IO::disable_connecting ();
1308 Stateful::save_extra_xml (node);
1310 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1311 load_options (*child);
1312 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1313 load_options (*child);
1315 error << _("Session: XML state has no options section") << endmsg;
1318 if (version >= 3000) {
1319 if ((child = find_named_node (node, "Metadata")) == 0) {
1320 warning << _("Session: XML state has no metadata section") << endmsg;
1321 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1326 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1327 _speakers->set_state (*child, version);
1330 if ((child = find_named_node (node, "Sources")) == 0) {
1331 error << _("Session: XML state has no sources section") << endmsg;
1333 } else if (load_sources (*child)) {
1337 if ((child = find_named_node (node, "TempoMap")) == 0) {
1338 error << _("Session: XML state has no Tempo Map section") << endmsg;
1340 } else if (_tempo_map->set_state (*child, version)) {
1344 if ((child = find_named_node (node, "Locations")) == 0) {
1345 error << _("Session: XML state has no locations section") << endmsg;
1347 } else if (_locations->set_state (*child, version)) {
1351 locations_changed ();
1353 if (_session_range_location) {
1354 AudioFileSource::set_header_position_offset (_session_range_location->start());
1357 if ((child = find_named_node (node, "Regions")) == 0) {
1358 error << _("Session: XML state has no Regions section") << endmsg;
1360 } else if (load_regions (*child)) {
1364 if ((child = find_named_node (node, "Playlists")) == 0) {
1365 error << _("Session: XML state has no playlists section") << endmsg;
1367 } else if (playlists->load (*this, *child)) {
1371 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1373 } else if (playlists->load_unused (*this, *child)) {
1377 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1378 if (load_compounds (*child)) {
1383 if (version >= 3000) {
1384 if ((child = find_named_node (node, "Bundles")) == 0) {
1385 warning << _("Session: XML state has no bundles section") << endmsg;
1388 /* We can't load Bundles yet as they need to be able
1389 to convert from port names to Port objects, which can't happen until
1391 _bundle_xml_node = new XMLNode (*child);
1395 if (version < 3000) {
1396 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1397 error << _("Session: XML state has no diskstreams section") << endmsg;
1399 } else if (load_diskstreams_2X (*child, version)) {
1404 if ((child = find_named_node (node, "Routes")) == 0) {
1405 error << _("Session: XML state has no routes section") << endmsg;
1407 } else if (load_routes (*child, version)) {
1411 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1412 _diskstreams_2X.clear ();
1414 if (version >= 3000) {
1416 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1417 error << _("Session: XML state has no route groups section") << endmsg;
1419 } else if (load_route_groups (*child, version)) {
1423 } else if (version < 3000) {
1425 if ((child = find_named_node (node, "EditGroups")) == 0) {
1426 error << _("Session: XML state has no edit groups section") << endmsg;
1428 } else if (load_route_groups (*child, version)) {
1432 if ((child = find_named_node (node, "MixGroups")) == 0) {
1433 error << _("Session: XML state has no mix groups section") << endmsg;
1435 } else if (load_route_groups (*child, version)) {
1440 if ((child = find_named_node (node, "Click")) == 0) {
1441 warning << _("Session: XML state has no click section") << endmsg;
1442 } else if (_click_io) {
1443 setup_click_state (&node);
1446 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1447 ControlProtocolManager::instance().set_state (*child, version);
1450 update_route_record_state ();
1452 /* here beginneth the second phase ... */
1454 StateReady (); /* EMIT SIGNAL */
1467 Session::load_routes (const XMLNode& node, int version)
1470 XMLNodeConstIterator niter;
1471 RouteList new_routes;
1473 nlist = node.children();
1477 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1479 boost::shared_ptr<Route> route;
1480 if (version < 3000) {
1481 route = XMLRouteFactory_2X (**niter, version);
1483 route = XMLRouteFactory (**niter, version);
1487 error << _("Session: cannot create Route from XML description.") << endmsg;
1491 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1493 new_routes.push_back (route);
1496 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1498 add_routes (new_routes, false, false, false);
1500 BootMessage (_("Finished adding tracks/busses"));
1505 boost::shared_ptr<Route>
1506 Session::XMLRouteFactory (const XMLNode& node, int version)
1508 boost::shared_ptr<Route> ret;
1510 if (node.name() != "Route") {
1514 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1516 DataType type = DataType::AUDIO;
1517 const XMLProperty* prop = node.property("default-type");
1520 type = DataType (prop->value());
1523 assert (type != DataType::NIL);
1527 boost::shared_ptr<Track> track;
1529 if (type == DataType::AUDIO) {
1530 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1532 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1535 if (track->init()) {
1539 if (track->set_state (node, version)) {
1543 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1544 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1549 enum Route::Flag flags = Route::Flag(0);
1550 const XMLProperty* prop = node.property("flags");
1552 flags = Route::Flag (string_2_enum (prop->value(), flags));
1555 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1557 if (r->init () == 0 && r->set_state (node, version) == 0) {
1558 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1559 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1568 boost::shared_ptr<Route>
1569 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1571 boost::shared_ptr<Route> ret;
1573 if (node.name() != "Route") {
1577 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1579 ds_prop = node.property (X_("diskstream"));
1582 DataType type = DataType::AUDIO;
1583 const XMLProperty* prop = node.property("default-type");
1586 type = DataType (prop->value());
1589 assert (type != DataType::NIL);
1593 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1594 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1598 if (i == _diskstreams_2X.end()) {
1599 error << _("Could not find diskstream for route") << endmsg;
1600 return boost::shared_ptr<Route> ();
1603 boost::shared_ptr<Track> track;
1605 if (type == DataType::AUDIO) {
1606 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1608 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1611 if (track->init()) {
1615 if (track->set_state (node, version)) {
1619 track->set_diskstream (*i);
1621 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1622 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1627 enum Route::Flag flags = Route::Flag(0);
1628 const XMLProperty* prop = node.property("flags");
1630 flags = Route::Flag (string_2_enum (prop->value(), flags));
1633 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1635 if (r->init () == 0 && r->set_state (node, version) == 0) {
1636 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1637 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1647 Session::load_regions (const XMLNode& node)
1650 XMLNodeConstIterator niter;
1651 boost::shared_ptr<Region> region;
1653 nlist = node.children();
1657 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1658 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1659 error << _("Session: cannot create Region from XML description.");
1660 const XMLProperty *name = (**niter).property("name");
1663 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1674 Session::load_compounds (const XMLNode& node)
1676 XMLNodeList calist = node.children();
1677 XMLNodeConstIterator caiter;
1678 XMLProperty *caprop;
1680 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1681 XMLNode* ca = *caiter;
1685 if ((caprop = ca->property (X_("original"))) == 0) {
1688 orig_id = caprop->value();
1690 if ((caprop = ca->property (X_("copy"))) == 0) {
1693 copy_id = caprop->value();
1695 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1696 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1698 if (!orig || !copy) {
1699 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1705 RegionFactory::add_compound_association (orig, copy);
1712 Session::load_nested_sources (const XMLNode& node)
1715 XMLNodeConstIterator niter;
1717 nlist = node.children();
1719 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1720 if ((*niter)->name() == "Source") {
1722 /* it may already exist, so don't recreate it unnecessarily
1725 XMLProperty* prop = (*niter)->property (X_("id"));
1727 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1731 ID source_id (prop->value());
1733 if (!source_by_id (source_id)) {
1736 SourceFactory::create (*this, **niter, true);
1738 catch (failed_constructor& err) {
1739 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1746 boost::shared_ptr<Region>
1747 Session::XMLRegionFactory (const XMLNode& node, bool full)
1749 const XMLProperty* type = node.property("type");
1753 const XMLNodeList& nlist = node.children();
1755 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1756 XMLNode *child = (*niter);
1757 if (child->name() == "NestedSource") {
1758 load_nested_sources (*child);
1762 if (!type || type->value() == "audio") {
1763 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1764 } else if (type->value() == "midi") {
1765 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1768 } catch (failed_constructor& err) {
1769 return boost::shared_ptr<Region> ();
1772 return boost::shared_ptr<Region> ();
1775 boost::shared_ptr<AudioRegion>
1776 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1778 const XMLProperty* prop;
1779 boost::shared_ptr<Source> source;
1780 boost::shared_ptr<AudioSource> as;
1782 SourceList master_sources;
1783 uint32_t nchans = 1;
1786 if (node.name() != X_("Region")) {
1787 return boost::shared_ptr<AudioRegion>();
1790 if ((prop = node.property (X_("channels"))) != 0) {
1791 nchans = atoi (prop->value().c_str());
1794 if ((prop = node.property ("name")) == 0) {
1795 cerr << "no name for this region\n";
1799 if ((prop = node.property (X_("source-0"))) == 0) {
1800 if ((prop = node.property ("source")) == 0) {
1801 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1802 return boost::shared_ptr<AudioRegion>();
1806 PBD::ID s_id (prop->value());
1808 if ((source = source_by_id (s_id)) == 0) {
1809 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1810 return boost::shared_ptr<AudioRegion>();
1813 as = boost::dynamic_pointer_cast<AudioSource>(source);
1815 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1816 return boost::shared_ptr<AudioRegion>();
1819 sources.push_back (as);
1821 /* pickup other channels */
1823 for (uint32_t n=1; n < nchans; ++n) {
1824 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1825 if ((prop = node.property (buf)) != 0) {
1827 PBD::ID id2 (prop->value());
1829 if ((source = source_by_id (id2)) == 0) {
1830 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1831 return boost::shared_ptr<AudioRegion>();
1834 as = boost::dynamic_pointer_cast<AudioSource>(source);
1836 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1837 return boost::shared_ptr<AudioRegion>();
1839 sources.push_back (as);
1843 for (uint32_t n = 0; n < nchans; ++n) {
1844 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1845 if ((prop = node.property (buf)) != 0) {
1847 PBD::ID id2 (prop->value());
1849 if ((source = source_by_id (id2)) == 0) {
1850 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1851 return boost::shared_ptr<AudioRegion>();
1854 as = boost::dynamic_pointer_cast<AudioSource>(source);
1856 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1857 return boost::shared_ptr<AudioRegion>();
1859 master_sources.push_back (as);
1864 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1866 /* a final detail: this is the one and only place that we know how long missing files are */
1868 if (region->whole_file()) {
1869 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1870 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1872 sfp->set_length (region->length());
1877 if (!master_sources.empty()) {
1878 if (master_sources.size() != nchans) {
1879 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1881 region->set_master_sources (master_sources);
1889 catch (failed_constructor& err) {
1890 return boost::shared_ptr<AudioRegion>();
1894 boost::shared_ptr<MidiRegion>
1895 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1897 const XMLProperty* prop;
1898 boost::shared_ptr<Source> source;
1899 boost::shared_ptr<MidiSource> ms;
1902 if (node.name() != X_("Region")) {
1903 return boost::shared_ptr<MidiRegion>();
1906 if ((prop = node.property ("name")) == 0) {
1907 cerr << "no name for this region\n";
1911 if ((prop = node.property (X_("source-0"))) == 0) {
1912 if ((prop = node.property ("source")) == 0) {
1913 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1914 return boost::shared_ptr<MidiRegion>();
1918 PBD::ID s_id (prop->value());
1920 if ((source = source_by_id (s_id)) == 0) {
1921 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1922 return boost::shared_ptr<MidiRegion>();
1925 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1927 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1928 return boost::shared_ptr<MidiRegion>();
1931 sources.push_back (ms);
1934 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1935 /* a final detail: this is the one and only place that we know how long missing files are */
1937 if (region->whole_file()) {
1938 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1939 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1941 sfp->set_length (region->length());
1949 catch (failed_constructor& err) {
1950 return boost::shared_ptr<MidiRegion>();
1955 Session::get_sources_as_xml ()
1958 XMLNode* node = new XMLNode (X_("Sources"));
1959 Glib::Threads::Mutex::Lock lm (source_lock);
1961 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1962 node->add_child_nocopy (i->second->get_state());
1969 Session::reset_write_sources (bool mark_write_complete, bool force)
1971 boost::shared_ptr<RouteList> rl = routes.reader();
1972 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1973 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1975 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1976 tr->reset_write_sources(mark_write_complete, force);
1977 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1983 Session::load_sources (const XMLNode& node)
1986 XMLNodeConstIterator niter;
1987 boost::shared_ptr<Source> source; /* don't need this but it stops some
1988 * versions of gcc complaining about
1989 * discarded return values.
1992 nlist = node.children();
1996 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1999 if ((source = XMLSourceFactory (**niter)) == 0) {
2000 error << _("Session: cannot create Source from XML description.") << endmsg;
2003 } catch (MissingSource& err) {
2007 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2008 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2009 PROGRAM_NAME) << endmsg;
2013 if (!no_questions_about_missing_files) {
2014 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2019 switch (user_choice) {
2021 /* user added a new search location, so try again */
2026 /* user asked to quit the entire session load
2031 no_questions_about_missing_files = true;
2035 no_questions_about_missing_files = true;
2042 case DataType::AUDIO:
2043 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2046 case DataType::MIDI:
2047 /* The MIDI file is actually missing so
2048 * just create a new one in the same
2049 * location. Do not announce its
2053 if (!Glib::path_is_absolute (err.path)) {
2054 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2056 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2061 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2062 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2063 /* reset ID to match the missing one */
2064 source->set_id (**niter);
2065 /* Now we can announce it */
2066 SourceFactory::SourceCreated (source);
2077 boost::shared_ptr<Source>
2078 Session::XMLSourceFactory (const XMLNode& node)
2080 if (node.name() != "Source") {
2081 return boost::shared_ptr<Source>();
2085 /* note: do peak building in another thread when loading session state */
2086 return SourceFactory::create (*this, node, true);
2089 catch (failed_constructor& err) {
2090 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2091 return boost::shared_ptr<Source>();
2096 Session::save_template (string template_name)
2098 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2102 bool absolute_path = Glib::path_is_absolute (template_name);
2104 /* directory to put the template in */
2105 std::string template_dir_path;
2107 if (!absolute_path) {
2108 std::string user_template_dir(user_template_directory());
2110 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2111 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2112 user_template_dir, g_strerror (errno)) << endmsg;
2116 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2118 template_dir_path = template_name;
2121 if (!ARDOUR::Profile->get_trx()) {
2122 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2123 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2124 template_dir_path) << endmsg;
2128 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2129 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2130 template_dir_path, g_strerror (errno)) << endmsg;
2136 std::string template_file_path;
2138 if (ARDOUR::Profile->get_trx()) {
2139 template_file_path = template_name;
2141 if (absolute_path) {
2142 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2144 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2148 SessionSaveUnderway (); /* EMIT SIGNAL */
2152 tree.set_root (&get_template());
2153 if (!tree.write (template_file_path)) {
2154 error << _("template not saved") << endmsg;
2158 if (!ARDOUR::Profile->get_trx()) {
2159 /* copy plugin state directory */
2161 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2163 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2164 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2165 template_plugin_state_path, g_strerror (errno)) << endmsg;
2168 copy_files (plugins_dir(), template_plugin_state_path);
2171 store_recent_templates (template_file_path);
2177 Session::refresh_disk_space ()
2179 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2181 Glib::Threads::Mutex::Lock lm (space_lock);
2183 /* get freespace on every FS that is part of the session path */
2185 _total_free_4k_blocks = 0;
2186 _total_free_4k_blocks_uncertain = false;
2188 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2190 struct statfs statfsbuf;
2191 statfs (i->path.c_str(), &statfsbuf);
2193 double const scale = statfsbuf.f_bsize / 4096.0;
2195 /* See if this filesystem is read-only */
2196 struct statvfs statvfsbuf;
2197 statvfs (i->path.c_str(), &statvfsbuf);
2199 /* f_bavail can be 0 if it is undefined for whatever
2200 filesystem we are looking at; Samba shares mounted
2201 via GVFS are an example of this.
2203 if (statfsbuf.f_bavail == 0) {
2204 /* block count unknown */
2206 i->blocks_unknown = true;
2207 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2208 /* read-only filesystem */
2210 i->blocks_unknown = false;
2212 /* read/write filesystem with known space */
2213 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2214 i->blocks_unknown = false;
2217 _total_free_4k_blocks += i->blocks;
2218 if (i->blocks_unknown) {
2219 _total_free_4k_blocks_uncertain = true;
2222 #elif defined PLATFORM_WINDOWS
2223 vector<string> scanned_volumes;
2224 vector<string>::iterator j;
2225 vector<space_and_path>::iterator i;
2226 DWORD nSectorsPerCluster, nBytesPerSector,
2227 nFreeClusters, nTotalClusters;
2231 _total_free_4k_blocks = 0;
2233 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2234 strncpy (disk_drive, (*i).path.c_str(), 3);
2238 volume_found = false;
2239 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2241 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2242 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2243 i->blocks = (uint32_t)(nFreeBytes / 4096);
2245 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2246 if (0 == j->compare(disk_drive)) {
2247 volume_found = true;
2252 if (!volume_found) {
2253 scanned_volumes.push_back(disk_drive);
2254 _total_free_4k_blocks += i->blocks;
2259 if (0 == _total_free_4k_blocks) {
2260 strncpy (disk_drive, path().c_str(), 3);
2263 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2265 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2266 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2267 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2274 Session::get_best_session_directory_for_new_audio ()
2276 vector<space_and_path>::iterator i;
2277 string result = _session_dir->root_path();
2279 /* handle common case without system calls */
2281 if (session_dirs.size() == 1) {
2285 /* OK, here's the algorithm we're following here:
2287 We want to select which directory to use for
2288 the next file source to be created. Ideally,
2289 we'd like to use a round-robin process so as to
2290 get maximum performance benefits from splitting
2291 the files across multiple disks.
2293 However, in situations without much diskspace, an
2294 RR approach may end up filling up a filesystem
2295 with new files while others still have space.
2296 Its therefore important to pay some attention to
2297 the freespace in the filesystem holding each
2298 directory as well. However, if we did that by
2299 itself, we'd keep creating new files in the file
2300 system with the most space until it was as full
2301 as all others, thus negating any performance
2302 benefits of this RAID-1 like approach.
2304 So, we use a user-configurable space threshold. If
2305 there are at least 2 filesystems with more than this
2306 much space available, we use RR selection between them.
2307 If not, then we pick the filesystem with the most space.
2309 This gets a good balance between the two
2313 refresh_disk_space ();
2315 int free_enough = 0;
2317 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2318 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2323 if (free_enough >= 2) {
2324 /* use RR selection process, ensuring that the one
2328 i = last_rr_session_dir;
2331 if (++i == session_dirs.end()) {
2332 i = session_dirs.begin();
2335 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2336 SessionDirectory sdir(i->path);
2337 if (sdir.create ()) {
2339 last_rr_session_dir = i;
2344 } while (i != last_rr_session_dir);
2348 /* pick FS with the most freespace (and that
2349 seems to actually work ...)
2352 vector<space_and_path> sorted;
2353 space_and_path_ascending_cmp cmp;
2355 sorted = session_dirs;
2356 sort (sorted.begin(), sorted.end(), cmp);
2358 for (i = sorted.begin(); i != sorted.end(); ++i) {
2359 SessionDirectory sdir(i->path);
2360 if (sdir.create ()) {
2362 last_rr_session_dir = i;
2372 Session::automation_dir () const
2374 return Glib::build_filename (_path, automation_dir_name);
2378 Session::analysis_dir () const
2380 return Glib::build_filename (_path, analysis_dir_name);
2384 Session::plugins_dir () const
2386 return Glib::build_filename (_path, plugins_dir_name);
2390 Session::externals_dir () const
2392 return Glib::build_filename (_path, externals_dir_name);
2396 Session::load_bundles (XMLNode const & node)
2398 XMLNodeList nlist = node.children();
2399 XMLNodeConstIterator niter;
2403 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2404 if ((*niter)->name() == "InputBundle") {
2405 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2406 } else if ((*niter)->name() == "OutputBundle") {
2407 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2409 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2418 Session::load_route_groups (const XMLNode& node, int version)
2420 XMLNodeList nlist = node.children();
2421 XMLNodeConstIterator niter;
2425 if (version >= 3000) {
2427 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2428 if ((*niter)->name() == "RouteGroup") {
2429 RouteGroup* rg = new RouteGroup (*this, "");
2430 add_route_group (rg);
2431 rg->set_state (**niter, version);
2435 } else if (version < 3000) {
2437 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2438 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2439 RouteGroup* rg = new RouteGroup (*this, "");
2440 add_route_group (rg);
2441 rg->set_state (**niter, version);
2450 state_file_filter (const string &str, void* /*arg*/)
2452 return (str.length() > strlen(statefile_suffix) &&
2453 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2457 remove_end(string state)
2459 string statename(state);
2461 string::size_type start,end;
2462 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2463 statename = statename.substr (start+1);
2466 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2467 end = statename.length();
2470 return string(statename.substr (0, end));
2474 Session::possible_states (string path)
2476 vector<string> states;
2477 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2479 transform(states.begin(), states.end(), states.begin(), remove_end);
2481 sort (states.begin(), states.end());
2487 Session::possible_states () const
2489 return possible_states(_path);
2493 Session::add_route_group (RouteGroup* g)
2495 _route_groups.push_back (g);
2496 route_group_added (g); /* EMIT SIGNAL */
2498 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2499 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2500 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2506 Session::remove_route_group (RouteGroup& rg)
2508 list<RouteGroup*>::iterator i;
2510 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2511 _route_groups.erase (i);
2514 route_group_removed (); /* EMIT SIGNAL */
2518 /** Set a new order for our route groups, without adding or removing any.
2519 * @param groups Route group list in the new order.
2522 Session::reorder_route_groups (list<RouteGroup*> groups)
2524 _route_groups = groups;
2526 route_groups_reordered (); /* EMIT SIGNAL */
2532 Session::route_group_by_name (string name)
2534 list<RouteGroup *>::iterator i;
2536 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2537 if ((*i)->name() == name) {
2545 Session::all_route_group() const
2547 return *_all_route_group;
2551 Session::add_commands (vector<Command*> const & cmds)
2553 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2559 Session::add_command (Command* const cmd)
2561 assert (_current_trans);
2562 DEBUG_UNDO_HISTORY (
2563 string_compose ("Current Undo Transaction %1, adding command: %2",
2564 _current_trans->name (),
2566 _current_trans->add_command (cmd);
2569 Session::begin_reversible_command (const string& name)
2571 begin_reversible_command (g_quark_from_string (name.c_str ()));
2574 /** Begin a reversible command using a GQuark to identify it.
2575 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2576 * but there must be as many begin...()s as there are commit...()s.
2579 Session::begin_reversible_command (GQuark q)
2581 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2582 to hold all the commands that are committed. This keeps the order of
2583 commands correct in the history.
2586 if (_current_trans == 0) {
2587 DEBUG_UNDO_HISTORY (string_compose (
2588 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2590 /* start a new transaction */
2591 assert (_current_trans_quarks.empty ());
2592 _current_trans = new UndoTransaction();
2593 _current_trans->set_name (g_quark_to_string (q));
2595 DEBUG_UNDO_HISTORY (
2596 string_compose ("Begin Reversible Command, current transaction: %1",
2597 _current_trans->name ()));
2600 _current_trans_quarks.push_front (q);
2604 Session::abort_reversible_command ()
2606 if (_current_trans != 0) {
2607 DEBUG_UNDO_HISTORY (
2608 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2609 _current_trans->clear();
2610 delete _current_trans;
2612 _current_trans_quarks.clear();
2617 Session::commit_reversible_command (Command *cmd)
2619 assert (_current_trans);
2620 assert (!_current_trans_quarks.empty ());
2625 DEBUG_UNDO_HISTORY (
2626 string_compose ("Current Undo Transaction %1, adding command: %2",
2627 _current_trans->name (),
2629 _current_trans->add_command (cmd);
2632 DEBUG_UNDO_HISTORY (
2633 string_compose ("Commit Reversible Command, current transaction: %1",
2634 _current_trans->name ()));
2636 _current_trans_quarks.pop_front ();
2638 if (!_current_trans_quarks.empty ()) {
2639 DEBUG_UNDO_HISTORY (
2640 string_compose ("Commit Reversible Command, transaction is not "
2641 "top-level, current transaction: %1",
2642 _current_trans->name ()));
2643 /* the transaction we're committing is not the top-level one */
2647 if (_current_trans->empty()) {
2648 /* no commands were added to the transaction, so just get rid of it */
2649 DEBUG_UNDO_HISTORY (
2650 string_compose ("Commit Reversible Command, No commands were "
2651 "added to current transaction: %1",
2652 _current_trans->name ()));
2653 delete _current_trans;
2658 gettimeofday (&now, 0);
2659 _current_trans->set_timestamp (now);
2661 _history.add (_current_trans);
2666 accept_all_audio_files (const string& path, void* /*arg*/)
2668 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2672 if (!AudioFileSource::safe_audio_file_extension (path)) {
2680 accept_all_midi_files (const string& path, void* /*arg*/)
2682 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2686 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2687 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2688 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2692 accept_all_state_files (const string& path, void* /*arg*/)
2694 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2698 std::string const statefile_ext (statefile_suffix);
2699 if (path.length() >= statefile_ext.length()) {
2700 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2707 Session::find_all_sources (string path, set<string>& result)
2712 if (!tree.read (path)) {
2716 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2721 XMLNodeConstIterator niter;
2723 nlist = node->children();
2727 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2731 if ((prop = (*niter)->property (X_("type"))) == 0) {
2735 DataType type (prop->value());
2737 if ((prop = (*niter)->property (X_("name"))) == 0) {
2741 if (Glib::path_is_absolute (prop->value())) {
2742 /* external file, ignore */
2750 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2751 result.insert (found_path);
2759 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2761 vector<string> state_files;
2763 string this_snapshot_path;
2769 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2770 ripped = ripped.substr (0, ripped.length() - 1);
2773 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2775 if (state_files.empty()) {
2780 this_snapshot_path = _path;
2781 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2782 this_snapshot_path += statefile_suffix;
2784 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2786 if (exclude_this_snapshot && *i == this_snapshot_path) {
2790 if (find_all_sources (*i, result) < 0) {
2798 struct RegionCounter {
2799 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2800 AudioSourceList::iterator iter;
2801 boost::shared_ptr<Region> region;
2804 RegionCounter() : count (0) {}
2808 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2810 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2811 return r.get_value_or (1);
2815 Session::cleanup_regions ()
2817 bool removed = false;
2818 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2820 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2822 uint32_t used = playlists->region_use_count (i->second);
2824 if (used == 0 && !i->second->automatic ()) {
2826 RegionFactory::map_remove (i->second);
2831 // re-check to remove parent references of compound regions
2832 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2833 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2836 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2837 if (0 == playlists->region_use_count (i->second)) {
2838 RegionFactory::map_remove (i->second);
2843 /* dump the history list */
2850 Session::cleanup_sources (CleanupReport& rep)
2852 // FIXME: needs adaptation to midi
2854 vector<boost::shared_ptr<Source> > dead_sources;
2857 vector<string> candidates;
2858 vector<string> unused;
2859 set<string> all_sources;
2868 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2870 /* consider deleting all unused playlists */
2872 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2877 /* sync the "all regions" property of each playlist with its current state
2880 playlists->sync_all_regions_with_regions ();
2882 /* find all un-used sources */
2887 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2889 SourceMap::iterator tmp;
2894 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2898 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2899 dead_sources.push_back (i->second);
2900 i->second->drop_references ();
2906 /* build a list of all the possible audio directories for the session */
2908 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2909 SessionDirectory sdir ((*i).path);
2910 asp += sdir.sound_path();
2912 audio_path += asp.to_string();
2915 /* build a list of all the possible midi directories for the session */
2917 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2918 SessionDirectory sdir ((*i).path);
2919 msp += sdir.midi_path();
2921 midi_path += msp.to_string();
2923 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2924 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2926 /* find all sources, but don't use this snapshot because the
2927 state file on disk still references sources we may have already
2931 find_all_sources_across_snapshots (all_sources, true);
2933 /* add our current source list
2936 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2937 boost::shared_ptr<FileSource> fs;
2938 SourceMap::iterator tmp = i;
2941 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2943 if (!fs->is_stub()) {
2945 if (playlists->source_use_count (fs) != 0) {
2946 all_sources.insert (fs->path());
2949 /* we might not remove this source from disk, because it may be used
2950 by other snapshots, but its not being used in this version
2951 so lets get rid of it now, along with any representative regions
2955 RegionFactory::remove_regions_using_source (i->second);
2957 // also remove source from all_sources
2959 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2960 spath = Glib::path_get_basename (*j);
2961 if (spath == i->second->name()) {
2962 all_sources.erase (j);
2975 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2980 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2982 tmppath1 = canonical_path (spath);
2983 tmppath2 = canonical_path ((*i));
2985 if (tmppath1 == tmppath2) {
2992 unused.push_back (spath);
2996 /* now try to move all unused files into the "dead" directory(ies) */
2998 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2999 struct stat statbuf;
3003 /* don't move the file across filesystems, just
3004 stick it in the `dead_dir_name' directory
3005 on whichever filesystem it was already on.
3008 if ((*x).find ("/sounds/") != string::npos) {
3010 /* old school, go up 1 level */
3012 newpath = Glib::path_get_dirname (*x); // "sounds"
3013 newpath = Glib::path_get_dirname (newpath); // "session-name"
3017 /* new school, go up 4 levels */
3019 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3020 newpath = Glib::path_get_dirname (newpath); // "session-name"
3021 newpath = Glib::path_get_dirname (newpath); // "interchange"
3022 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3025 newpath = Glib::build_filename (newpath, dead_dir_name);
3027 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3028 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3032 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3034 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3036 /* the new path already exists, try versioning */
3038 char buf[PATH_MAX+1];
3042 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3045 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3046 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3050 if (version == 999) {
3051 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3055 newpath = newpath_v;
3060 /* it doesn't exist, or we can't read it or something */
3064 stat ((*x).c_str(), &statbuf);
3066 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3067 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3068 (*x), newpath, strerror (errno))
3073 /* see if there an easy to find peakfile for this file, and remove it.
3076 string base = Glib::path_get_basename (*x);
3077 base += "%A"; /* this is what we add for the channel suffix of all native files,
3078 or for the first channel of embedded files. it will miss
3079 some peakfiles for other channels
3081 string peakpath = construct_peak_filepath (base);
3083 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3084 if (::g_unlink (peakpath.c_str()) != 0) {
3085 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3086 peakpath, _path, strerror (errno))
3088 /* try to back out */
3089 ::rename (newpath.c_str(), _path.c_str());
3094 rep.paths.push_back (*x);
3095 rep.space += statbuf.st_size;
3098 /* dump the history list */
3102 /* save state so we don't end up a session file
3103 referring to non-existent sources.
3110 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3116 Session::cleanup_trash_sources (CleanupReport& rep)
3118 // FIXME: needs adaptation for MIDI
3120 vector<space_and_path>::iterator i;
3126 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3128 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3130 clear_directory (dead_dir, &rep.space, &rep.paths);
3137 Session::set_dirty ()
3139 /* never mark session dirty during loading */
3141 if (_state_of_the_state & Loading) {
3145 bool was_dirty = dirty();
3147 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3151 DirtyChanged(); /* EMIT SIGNAL */
3157 Session::set_clean ()
3159 bool was_dirty = dirty();
3161 _state_of_the_state = Clean;
3165 DirtyChanged(); /* EMIT SIGNAL */
3170 Session::set_deletion_in_progress ()
3172 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3176 Session::clear_deletion_in_progress ()
3178 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3182 Session::add_controllable (boost::shared_ptr<Controllable> c)
3184 /* this adds a controllable to the list managed by the Session.
3185 this is a subset of those managed by the Controllable class
3186 itself, and represents the only ones whose state will be saved
3187 as part of the session.
3190 Glib::Threads::Mutex::Lock lm (controllables_lock);
3191 controllables.insert (c);
3194 struct null_deleter { void operator()(void const *) const {} };
3197 Session::remove_controllable (Controllable* c)
3199 if (_state_of_the_state & Deletion) {
3203 Glib::Threads::Mutex::Lock lm (controllables_lock);
3205 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3207 if (x != controllables.end()) {
3208 controllables.erase (x);
3212 boost::shared_ptr<Controllable>
3213 Session::controllable_by_id (const PBD::ID& id)
3215 Glib::Threads::Mutex::Lock lm (controllables_lock);
3217 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3218 if ((*i)->id() == id) {
3223 return boost::shared_ptr<Controllable>();
3226 boost::shared_ptr<Controllable>
3227 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3229 boost::shared_ptr<Controllable> c;
3230 boost::shared_ptr<Route> r;
3232 switch (desc.top_level_type()) {
3233 case ControllableDescriptor::NamedRoute:
3235 std::string str = desc.top_level_name();
3236 if (str == "Master" || str == "master") {
3238 } else if (str == "control" || str == "listen") {
3241 r = route_by_name (desc.top_level_name());
3246 case ControllableDescriptor::RemoteControlID:
3247 r = route_by_remote_id (desc.rid());
3255 switch (desc.subtype()) {
3256 case ControllableDescriptor::Gain:
3257 c = r->gain_control ();
3260 case ControllableDescriptor::Trim:
3261 c = r->trim()->gain_control ();
3264 case ControllableDescriptor::Solo:
3265 c = r->solo_control();
3268 case ControllableDescriptor::Mute:
3269 c = r->mute_control();
3272 case ControllableDescriptor::Recenable:
3274 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3277 c = t->rec_enable_control ();
3282 case ControllableDescriptor::PanDirection:
3284 c = r->pannable()->pan_azimuth_control;
3288 case ControllableDescriptor::PanWidth:
3290 c = r->pannable()->pan_width_control;
3294 case ControllableDescriptor::PanElevation:
3296 c = r->pannable()->pan_elevation_control;
3300 case ControllableDescriptor::Balance:
3301 /* XXX simple pan control */
3304 case ControllableDescriptor::PluginParameter:
3306 uint32_t plugin = desc.target (0);
3307 uint32_t parameter_index = desc.target (1);
3309 /* revert to zero based counting */
3315 if (parameter_index > 0) {
3319 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3322 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3323 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3328 case ControllableDescriptor::SendGain:
3330 uint32_t send = desc.target (0);
3332 /* revert to zero-based counting */
3338 boost::shared_ptr<Processor> p = r->nth_send (send);
3341 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3342 boost::shared_ptr<Amp> a = s->amp();
3345 c = s->amp()->gain_control();
3352 /* relax and return a null pointer */
3360 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3363 Stateful::add_instant_xml (node, _path);
3366 if (write_to_config) {
3367 Config->add_instant_xml (node);
3372 Session::instant_xml (const string& node_name)
3374 return Stateful::instant_xml (node_name, _path);
3378 Session::save_history (string snapshot_name)
3386 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3387 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3391 if (snapshot_name.empty()) {
3392 snapshot_name = _current_snapshot_name;
3395 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3396 const string backup_filename = history_filename + backup_suffix;
3397 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3398 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3400 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3401 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3402 error << _("could not backup old history file, current history not saved") << endmsg;
3407 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3409 if (!tree.write (xml_path))
3411 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3413 if (g_remove (xml_path.c_str()) != 0) {
3414 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3415 xml_path, g_strerror (errno)) << endmsg;
3417 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3418 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3419 backup_path, g_strerror (errno)) << endmsg;
3429 Session::restore_history (string snapshot_name)
3433 if (snapshot_name.empty()) {
3434 snapshot_name = _current_snapshot_name;
3437 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3438 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3440 info << "Loading history from " << xml_path << endmsg;
3442 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3443 info << string_compose (_("%1: no history file \"%2\" for this session."),
3444 _name, xml_path) << endmsg;
3448 if (!tree.read (xml_path)) {
3449 error << string_compose (_("Could not understand session history file \"%1\""),
3450 xml_path) << endmsg;
3457 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3460 UndoTransaction* ut = new UndoTransaction ();
3463 ut->set_name(t->property("name")->value());
3464 stringstream ss(t->property("tv-sec")->value());
3466 ss.str(t->property("tv-usec")->value());
3468 ut->set_timestamp(tv);
3470 for (XMLNodeConstIterator child_it = t->children().begin();
3471 child_it != t->children().end(); child_it++)
3473 XMLNode *n = *child_it;
3476 if (n->name() == "MementoCommand" ||
3477 n->name() == "MementoUndoCommand" ||
3478 n->name() == "MementoRedoCommand") {
3480 if ((c = memento_command_factory(n))) {
3484 } else if (n->name() == "NoteDiffCommand") {
3485 PBD::ID id (n->property("midi-source")->value());
3486 boost::shared_ptr<MidiSource> midi_source =
3487 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3489 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3491 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3494 } else if (n->name() == "SysExDiffCommand") {
3496 PBD::ID id (n->property("midi-source")->value());
3497 boost::shared_ptr<MidiSource> midi_source =
3498 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3500 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3502 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3505 } else if (n->name() == "PatchChangeDiffCommand") {
3507 PBD::ID id (n->property("midi-source")->value());
3508 boost::shared_ptr<MidiSource> midi_source =
3509 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3511 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3513 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3516 } else if (n->name() == "StatefulDiffCommand") {
3517 if ((c = stateful_diff_command_factory (n))) {
3518 ut->add_command (c);
3521 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3532 Session::config_changed (std::string p, bool ours)
3538 if (p == "seamless-loop") {
3540 } else if (p == "rf-speed") {
3542 } else if (p == "auto-loop") {
3544 } else if (p == "auto-input") {
3546 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3547 /* auto-input only makes a difference if we're rolling */
3548 set_track_monitor_input_status (!config.get_auto_input());
3551 } else if (p == "punch-in") {
3555 if ((location = _locations->auto_punch_location()) != 0) {
3557 if (config.get_punch_in ()) {
3558 replace_event (SessionEvent::PunchIn, location->start());
3560 remove_event (location->start(), SessionEvent::PunchIn);
3564 } else if (p == "punch-out") {
3568 if ((location = _locations->auto_punch_location()) != 0) {
3570 if (config.get_punch_out()) {
3571 replace_event (SessionEvent::PunchOut, location->end());
3573 clear_events (SessionEvent::PunchOut);
3577 } else if (p == "edit-mode") {
3579 Glib::Threads::Mutex::Lock lm (playlists->lock);
3581 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3582 (*i)->set_edit_mode (Config->get_edit_mode ());
3585 } else if (p == "use-video-sync") {
3587 waiting_for_sync_offset = config.get_use_video_sync();
3589 } else if (p == "mmc-control") {
3591 //poke_midi_thread ();
3593 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3595 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3597 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3599 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3601 } else if (p == "midi-control") {
3603 //poke_midi_thread ();
3605 } else if (p == "raid-path") {
3607 setup_raid_path (config.get_raid_path());
3609 } else if (p == "timecode-format") {
3613 } else if (p == "video-pullup") {
3617 } else if (p == "seamless-loop") {
3619 if (play_loop && transport_rolling()) {
3620 // to reset diskstreams etc
3621 request_play_loop (true);
3624 } else if (p == "rf-speed") {
3626 cumulative_rf_motion = 0;
3629 } else if (p == "click-sound") {
3631 setup_click_sounds (1);
3633 } else if (p == "click-emphasis-sound") {
3635 setup_click_sounds (-1);
3637 } else if (p == "clicking") {
3639 if (Config->get_clicking()) {
3640 if (_click_io && click_data) { // don't require emphasis data
3647 } else if (p == "click-gain") {
3650 _click_gain->set_gain (Config->get_click_gain(), this);
3653 } else if (p == "send-mtc") {
3655 if (Config->get_send_mtc ()) {
3656 /* mark us ready to send */
3657 next_quarter_frame_to_send = 0;
3660 } else if (p == "send-mmc") {
3662 _mmc->enable_send (Config->get_send_mmc ());
3664 } else if (p == "midi-feedback") {
3666 session_midi_feedback = Config->get_midi_feedback();
3668 } else if (p == "jack-time-master") {
3670 engine().reset_timebase ();
3672 } else if (p == "native-file-header-format") {
3674 if (!first_file_header_format_reset) {
3675 reset_native_file_format ();
3678 first_file_header_format_reset = false;
3680 } else if (p == "native-file-data-format") {
3682 if (!first_file_data_format_reset) {
3683 reset_native_file_format ();
3686 first_file_data_format_reset = false;
3688 } else if (p == "external-sync") {
3689 if (!config.get_external_sync()) {
3690 drop_sync_source ();
3692 switch_to_sync_source (Config->get_sync_source());
3694 } else if (p == "denormal-model") {
3696 } else if (p == "history-depth") {
3697 set_history_depth (Config->get_history_depth());
3698 } else if (p == "remote-model") {
3699 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3702 } else if (p == "initial-program-change") {
3704 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3707 buf[0] = MIDI::program; // channel zero by default
3708 buf[1] = (Config->get_initial_program_change() & 0x7f);
3710 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3712 } else if (p == "solo-mute-override") {
3713 // catch_up_on_solo_mute_override ();
3714 } else if (p == "listen-position" || p == "pfl-position") {
3715 listen_position_changed ();
3716 } else if (p == "solo-control-is-listen-control") {
3717 solo_control_mode_changed ();
3718 } else if (p == "solo-mute-gain") {
3719 _solo_cut_control->Changed();
3720 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3721 last_timecode_valid = false;
3722 } else if (p == "playback-buffer-seconds") {
3723 AudioSource::allocate_working_buffers (frame_rate());
3724 } else if (p == "ltc-source-port") {
3725 reconnect_ltc_input ();
3726 } else if (p == "ltc-sink-port") {
3727 reconnect_ltc_output ();
3728 } else if (p == "timecode-generator-offset") {
3729 ltc_tx_parse_offset();
3730 } else if (p == "auto-return-target-list") {
3731 follow_playhead_priority ();
3738 Session::set_history_depth (uint32_t d)
3740 _history.set_depth (d);
3744 Session::load_diskstreams_2X (XMLNode const & node, int)
3747 XMLNodeConstIterator citer;
3749 clist = node.children();
3751 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3754 /* diskstreams added automatically by DiskstreamCreated handler */
3755 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3756 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3757 _diskstreams_2X.push_back (dsp);
3759 error << _("Session: unknown diskstream type in XML") << endmsg;
3763 catch (failed_constructor& err) {
3764 error << _("Session: could not load diskstream via XML state") << endmsg;
3772 /** Connect things to the MMC object */
3774 Session::setup_midi_machine_control ()
3776 _mmc = new MIDI::MachineControl;
3777 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3779 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3780 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3781 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3782 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3783 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3784 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3785 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3786 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3787 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3788 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3789 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3790 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3791 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3793 /* also handle MIDI SPP because its so common */
3795 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3796 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3797 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3800 boost::shared_ptr<Controllable>
3801 Session::solo_cut_control() const
3803 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3804 controls in Ardour that currently get presented to the user in the GUI that require
3805 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3807 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3808 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3812 return _solo_cut_control;
3816 Session::rename (const std::string& new_name)
3818 string legal_name = legalize_for_path (new_name);
3824 string const old_sources_root = _session_dir->sources_root();
3826 if (!_writable || (_state_of_the_state & CannotSave)) {
3827 error << _("Cannot rename read-only session.") << endmsg;
3828 return 0; // don't show "messed up" warning
3830 if (record_status() == Recording) {
3831 error << _("Cannot rename session while recording") << endmsg;
3832 return 0; // don't show "messed up" warning
3835 StateProtector stp (this);
3840 * interchange subdirectory
3844 * Backup files are left unchanged and not renamed.
3847 /* Windows requires that we close all files before attempting the
3848 * rename. This works on other platforms, but isn't necessary there.
3849 * Leave it in place for all platforms though, since it may help
3850 * catch issues that could arise if the way Source files work ever
3851 * change (since most developers are not using Windows).
3854 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3855 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3861 /* pass one: not 100% safe check that the new directory names don't
3865 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3869 /* this is a stupid hack because Glib::path_get_dirname() is
3870 * lexical-only, and so passing it /a/b/c/ gives a different
3871 * result than passing it /a/b/c ...
3874 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3875 oldstr = oldstr.substr (0, oldstr.length() - 1);
3878 string base = Glib::path_get_dirname (oldstr);
3880 newstr = Glib::build_filename (base, legal_name);
3882 cerr << "Looking for " << newstr << endl;
3884 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3885 cerr << " exists\n";
3894 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3900 /* this is a stupid hack because Glib::path_get_dirname() is
3901 * lexical-only, and so passing it /a/b/c/ gives a different
3902 * result than passing it /a/b/c ...
3905 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3906 oldstr = oldstr.substr (0, oldstr.length() - 1);
3909 string base = Glib::path_get_dirname (oldstr);
3910 newstr = Glib::build_filename (base, legal_name);
3912 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3914 cerr << "Rename " << oldstr << " => " << newstr << endl;
3915 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3916 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3917 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3921 /* Reset path in "session dirs" */
3926 /* reset primary SessionDirectory object */
3929 (*_session_dir) = newstr;
3934 /* now rename directory below session_dir/interchange */
3936 string old_interchange_dir;
3937 string new_interchange_dir;
3939 /* use newstr here because we renamed the path
3940 * (folder/directory) that used to be oldstr to newstr above
3943 v.push_back (newstr);
3944 v.push_back (interchange_dir_name);
3945 v.push_back (Glib::path_get_basename (oldstr));
3947 old_interchange_dir = Glib::build_filename (v);
3950 v.push_back (newstr);
3951 v.push_back (interchange_dir_name);
3952 v.push_back (legal_name);
3954 new_interchange_dir = Glib::build_filename (v);
3956 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3958 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3959 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3960 old_interchange_dir, new_interchange_dir,
3963 error << string_compose (_("renaming %s as %2 failed (%3)"),
3964 old_interchange_dir, new_interchange_dir,
3973 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3974 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3976 cerr << "Rename " << oldstr << " => " << newstr << endl;
3978 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3979 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3980 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3986 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3988 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3989 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3991 cerr << "Rename " << oldstr << " => " << newstr << endl;
3993 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3994 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3995 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4000 /* remove old name from recent sessions */
4001 remove_recent_sessions (_path);
4004 /* update file source paths */
4006 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4007 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4009 string p = fs->path ();
4010 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4012 SourceFactory::setup_peakfile(i->second, true);
4016 _current_snapshot_name = new_name;
4021 /* save state again to get everything just right */
4023 save_state (_current_snapshot_name);
4025 /* add to recent sessions */
4027 store_recent_sessions (new_name, _path);
4033 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4035 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4039 if (!tree.read (xmlpath)) {
4047 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4050 bool found_sr = false;
4051 bool found_data_format = false;
4053 if (get_session_info_from_path (tree, xmlpath)) {
4059 const XMLProperty* prop;
4060 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4061 sample_rate = atoi (prop->value());
4065 const XMLNodeList& children (tree.root()->children());
4066 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4067 const XMLNode* child = *c;
4068 if (child->name() == "Config") {
4069 const XMLNodeList& options (child->children());
4070 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4071 const XMLNode* option = *oc;
4072 const XMLProperty* name = option->property("name");
4078 if (name->value() == "native-file-data-format") {
4079 const XMLProperty* value = option->property ("value");
4081 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4083 found_data_format = true;
4089 if (found_data_format) {
4094 return !(found_sr && found_data_format); // zero if they are both found
4097 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4098 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4101 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4105 SourcePathMap source_path_map;
4107 boost::shared_ptr<AudioFileSource> afs;
4112 Glib::Threads::Mutex::Lock lm (source_lock);
4114 cerr << " total sources = " << sources.size();
4116 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4117 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4123 if (fs->within_session()) {
4127 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4128 source_path_map[fs->path()].push_back (fs);
4130 SeveralFileSources v;
4132 source_path_map.insert (make_pair (fs->path(), v));
4138 cerr << " fsources = " << total << endl;
4140 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4142 /* tell caller where we are */
4144 string old_path = i->first;
4146 callback (n, total, old_path);
4148 cerr << old_path << endl;
4152 switch (i->second.front()->type()) {
4153 case DataType::AUDIO:
4154 new_path = new_audio_source_path_for_embedded (old_path);
4157 case DataType::MIDI:
4158 /* XXX not implemented yet */
4162 if (new_path.empty()) {
4166 cerr << "Move " << old_path << " => " << new_path << endl;
4168 if (!copy_file (old_path, new_path)) {
4169 cerr << "failed !\n";
4173 /* make sure we stop looking in the external
4174 dir/folder. Remember, this is an all-or-nothing
4175 operations, it doesn't merge just some files.
4177 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4179 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4180 (*f)->set_path (new_path);
4185 save_state ("", false, false);
4191 bool accept_all_files (string const &, void *)
4197 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4199 /* 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.
4204 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4206 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4208 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4210 v.push_back (new_session_folder); /* full path */
4211 v.push_back (interchange_dir_name);
4212 v.push_back (new_session_path); /* just one directory/folder */
4213 v.push_back (typedir);
4214 v.push_back (Glib::path_get_basename (old_path));
4216 return Glib::build_filename (v);
4220 Session::save_as (SaveAs& saveas)
4222 vector<string> files;
4223 string current_folder = Glib::path_get_dirname (_path);
4224 string new_folder = legalize_for_path (saveas.new_name);
4225 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4226 int64_t total_bytes = 0;
4230 int32_t internal_file_cnt = 0;
4232 vector<string> do_not_copy_extensions;
4233 do_not_copy_extensions.push_back (statefile_suffix);
4234 do_not_copy_extensions.push_back (pending_suffix);
4235 do_not_copy_extensions.push_back (backup_suffix);
4236 do_not_copy_extensions.push_back (temp_suffix);
4237 do_not_copy_extensions.push_back (history_suffix);
4239 /* get total size */
4241 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4243 /* need to clear this because
4244 * find_files_matching_filter() is cumulative
4249 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4251 all += files.size();
4253 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4255 g_stat ((*i).c_str(), &gsb);
4256 total_bytes += gsb.st_size;
4260 /* save old values so we can switch back if we are not switching to the new session */
4262 string old_path = _path;
4263 string old_name = _name;
4264 string old_snapshot = _current_snapshot_name;
4265 string old_sd = _session_dir->root_path();
4266 vector<string> old_search_path[DataType::num_types];
4267 string old_config_search_path[DataType::num_types];
4269 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4270 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4271 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4272 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4274 /* switch session directory */
4276 (*_session_dir) = to_dir;
4278 /* create new tree */
4280 if (!_session_dir->create()) {
4281 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4286 /* copy all relevant files. Find each location in session_dirs,
4287 * and copy files from there to target.
4290 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4292 /* need to clear this because
4293 * find_files_matching_filter() is cumulative
4298 const size_t prefix_len = (*sd).path.size();
4300 /* Work just on the files within this session dir */
4302 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4304 /* add dir separator to protect against collisions with
4305 * track names (e.g. track named "audiofiles" or
4309 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4310 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4311 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4313 /* copy all the files. Handling is different for media files
4314 than others because of the *silly* subtree we have below the interchange
4315 folder. That really was a bad idea, but I'm not fixing it as part of
4316 implementing ::save_as().
4319 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4321 std::string from = *i;
4324 string filename = Glib::path_get_basename (from);
4325 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4326 if (filename == ".DS_STORE") {
4331 if (from.find (audiofile_dir_string) != string::npos) {
4333 /* audio file: only copy if asked */
4335 if (saveas.include_media && saveas.copy_media) {
4337 string to = make_new_media_path (*i, to_dir, new_folder);
4339 info << "media file copying from " << from << " to " << to << endmsg;
4341 if (!copy_file (from, to)) {
4342 throw Glib::FileError (Glib::FileError::IO_ERROR,
4343 string_compose(_("\ncopying \"%1\" failed !"), from));
4347 /* we found media files inside the session folder */
4349 internal_file_cnt++;
4351 } else if (from.find (midifile_dir_string) != string::npos) {
4353 /* midi file: always copy unless
4354 * creating an empty new session
4357 if (saveas.include_media) {
4359 string to = make_new_media_path (*i, to_dir, new_folder);
4361 info << "media file copying from " << from << " to " << to << endmsg;
4363 if (!copy_file (from, to)) {
4364 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4368 /* we found media files inside the session folder */
4370 internal_file_cnt++;
4372 } else if (from.find (analysis_dir_string) != string::npos) {
4374 /* make sure analysis dir exists in
4375 * new session folder, but we're not
4376 * copying analysis files here, see
4380 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4385 /* normal non-media file. Don't copy state, history, etc.
4388 bool do_copy = true;
4390 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4391 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4392 /* end of filename matches extension, do not copy file */
4398 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4399 /* don't copy peakfiles if
4400 * we're not copying media
4406 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4408 info << "attempting to make directory/folder " << to << endmsg;
4410 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4411 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4414 info << "attempting to copy " << from << " to " << to << endmsg;
4416 if (!copy_file (from, to)) {
4417 throw Glib::FileError (Glib::FileError::IO_ERROR,
4418 string_compose(_("\ncopying \"%1\" failed !"), from));
4423 /* measure file size even if we're not going to copy so that our Progress
4424 signals are correct, since we included these do-not-copy files
4425 in the computation of the total size and file count.
4429 g_stat (from.c_str(), &gsb);
4430 copied += gsb.st_size;
4433 double fraction = (double) copied / total_bytes;
4435 bool keep_going = true;
4437 if (saveas.copy_media) {
4439 /* no need or expectation of this if
4440 * media is not being copied, because
4441 * it will be fast(ish).
4444 /* tell someone "X percent, file M of N"; M is one-based */
4446 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4454 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4460 /* copy optional folders, if any */
4462 string old = plugins_dir ();
4463 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4464 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4465 copy_files (old, newdir);
4468 old = externals_dir ();
4469 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4470 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4471 copy_files (old, newdir);
4474 old = automation_dir ();
4475 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4476 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4477 copy_files (old, newdir);
4480 if (saveas.include_media) {
4482 if (saveas.copy_media) {
4483 #ifndef PLATFORM_WINDOWS
4484 /* There are problems with analysis files on
4485 * Windows, because they used a colon in their
4486 * names as late as 4.0. Colons are not legal
4487 * under Windows even if NTFS allows them.
4489 * This is a tricky problem to solve so for
4490 * just don't copy these files. They will be
4491 * regenerated as-needed anyway, subject to the
4492 * existing issue that the filenames will be
4493 * rejected by Windows, which is a separate
4494 * problem (though related).
4497 /* only needed if we are copying media, since the
4498 * analysis data refers to media data
4501 old = analysis_dir ();
4502 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4503 string newdir = Glib::build_filename (to_dir, "analysis");
4504 copy_files (old, newdir);
4506 #endif /* PLATFORM_WINDOWS */
4512 _current_snapshot_name = saveas.new_name;
4513 _name = saveas.new_name;
4515 if (saveas.include_media && !saveas.copy_media) {
4517 /* reset search paths of the new session (which we're pretending to be right now) to
4518 include the original session search path, so we can still find all audio.
4521 if (internal_file_cnt) {
4522 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4523 ensure_search_path_includes (*s, DataType::AUDIO);
4524 cerr << "be sure to include " << *s << " for audio" << endl;
4527 /* we do not do this for MIDI because we copy
4528 all MIDI files if saveas.include_media is
4534 bool was_dirty = dirty ();
4536 save_state ("", false, false, !saveas.include_media);
4537 save_default_options ();
4539 if (saveas.copy_media && saveas.copy_external) {
4540 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4541 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4545 saveas.final_session_folder_name = _path;
4547 store_recent_sessions (_name, _path);
4549 if (!saveas.switch_to) {
4551 /* switch back to the way things were */
4555 _current_snapshot_name = old_snapshot;
4557 (*_session_dir) = old_sd;
4563 if (internal_file_cnt) {
4564 /* reset these to their original values */
4565 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4566 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4571 /* prune session dirs, and update disk space statistics
4576 session_dirs.clear ();
4577 session_dirs.push_back (sp);
4578 refresh_disk_space ();
4580 /* ensure that all existing tracks reset their current capture source paths
4582 reset_write_sources (true, true);
4584 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4585 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4588 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4589 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4595 if (fs->within_session()) {
4596 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4597 fs->set_path (newpath);
4602 } catch (Glib::FileError& e) {
4604 saveas.failure_message = e.what();
4606 /* recursively remove all the directories */
4608 remove_directory (to_dir);
4616 saveas.failure_message = _("unknown reason");
4618 /* recursively remove all the directories */
4620 remove_directory (to_dir);