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>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/boost_debug.h"
66 #include "pbd/basename.h"
67 #include "pbd/controllable_descriptor.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pathscanner.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/convert.h"
76 #include "pbd/clear_dir.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/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/proxy_controllable.h"
104 #include "ardour/recent_sessions.h"
105 #include "ardour/region_factory.h"
106 #include "ardour/route_group.h"
107 #include "ardour/send.h"
108 #include "ardour/session.h"
109 #include "ardour/session_directory.h"
110 #include "ardour/session_metadata.h"
111 #include "ardour/session_playlists.h"
112 #include "ardour/session_state_utils.h"
113 #include "ardour/silentfilesource.h"
114 #include "ardour/sndfilesource.h"
115 #include "ardour/source_factory.h"
116 #include "ardour/speakers.h"
117 #include "ardour/template_utils.h"
118 #include "ardour/tempo.h"
119 #include "ardour/ticker.h"
120 #include "ardour/user_bundle.h"
122 #include "control_protocol/control_protocol.h"
128 using namespace ARDOUR;
132 Session::pre_engine_init (string fullpath)
134 if (fullpath.empty()) {
136 throw failed_constructor();
139 /* discover canonical fullpath */
141 _path = canonical_path(fullpath);
143 /* we require _path to end with a dir separator */
145 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
146 _path += G_DIR_SEPARATOR;
151 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
153 /* finish initialization that can't be done in a normal C++ constructor
157 timerclear (&last_mmc_step);
158 g_atomic_int_set (&processing_prohibited, 0);
159 g_atomic_int_set (&_record_status, Disabled);
160 g_atomic_int_set (&_playback_load, 100);
161 g_atomic_int_set (&_capture_load, 100);
163 _all_route_group->set_active (true, this);
164 interpolation.add_channel_to (0, 0);
166 if (config.get_use_video_sync()) {
167 waiting_for_sync_offset = true;
169 waiting_for_sync_offset = false;
172 last_rr_session_dir = session_dirs.begin();
174 set_history_depth (Config->get_history_depth());
176 /* default: assume simple stereo speaker configuration */
178 _speakers->setup_default_speakers (2);
180 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
181 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
182 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
183 add_controllable (_solo_cut_control);
185 /* These are all static "per-class" signals */
187 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
188 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
189 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
190 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
191 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
193 /* stop IO objects from doing stuff until we're ready for them */
195 Delivery::disable_panners ();
196 IO::disable_connecting ();
198 AudioFileSource::set_peak_dir (_session_dir->peak_path());
202 Session::post_engine_init ()
204 BootMessage (_("Set block size and sample rate"));
206 set_block_size (_engine.samples_per_cycle());
207 set_frame_rate (_engine.sample_rate());
209 BootMessage (_("Using configuration"));
211 _midi_ports = new MidiPortManager;
213 MIDISceneChanger* msc;
215 _scene_changer = msc = new MIDISceneChanger (*this);
216 msc->set_input_port (scene_input_port());
217 msc->set_output_port (scene_out());
219 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
220 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
222 setup_midi_machine_control ();
224 if (_butler->start_thread()) {
228 if (start_midi_thread ()) {
232 setup_click_sounds (0);
233 setup_midi_control ();
235 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
236 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
239 /* tempo map requires sample rate knowledge */
241 _tempo_map = new TempoMap (_current_frame_rate);
242 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
244 /* MidiClock requires a tempo map */
246 midi_clock = new MidiClockTicker ();
247 midi_clock->set_session (this);
249 /* crossfades require sample rate knowledge */
251 SndFileSource::setup_standard_crossfades (*this, frame_rate());
252 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
254 AudioDiskstream::allocate_working_buffers();
255 refresh_disk_space ();
257 /* we're finally ready to call set_state() ... all objects have
258 * been created, the engine is running.
262 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
266 // set_state() will call setup_raid_path(), but if it's a new session we need
267 // to call setup_raid_path() here.
268 setup_raid_path (_path);
273 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
274 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
276 Config->map_parameters (ff);
277 config.map_parameters (ft);
279 /* Reset all panners */
281 Delivery::reset_panners ();
283 /* this will cause the CPM to instantiate any protocols that are in use
284 * (or mandatory), which will pass it this Session, and then call
285 * set_state() on each instantiated protocol to match stored state.
288 ControlProtocolManager::instance().set_session (this);
290 /* This must be done after the ControlProtocolManager set_session above,
291 as it will set states for ports which the ControlProtocolManager creates.
294 // XXX set state of MIDI::Port's
295 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
297 /* And this must be done after the MIDI::Manager::set_port_states as
298 * it will try to make connections whose details are loaded by set_port_states.
303 /* Let control protocols know that we are now all connected, so they
304 * could start talking to surfaces if they want to.
307 ControlProtocolManager::instance().midi_connectivity_established ();
309 if (_is_new && !no_auto_connect()) {
310 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
311 auto_connect_master_bus ();
314 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
316 /* update latencies */
318 initialize_latencies ();
320 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
321 _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
323 } catch (AudioEngine::PortRegistrationFailure& err) {
324 /* handle this one in a different way than all others, so that its clear what happened */
325 error << err.what() << endmsg;
331 BootMessage (_("Reset Remote Controls"));
333 // send_full_time_code (0);
334 _engine.transport_locate (0);
336 _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
337 _mmc->send (MIDI::MachineControlCommand (Timecode::Time ()));
339 MIDI::Name::MidiPatchManager::instance().set_session (this);
342 /* initial program change will be delivered later; see ::config_changed() */
344 _state_of_the_state = Clean;
346 Port::set_connecting_blocked (false);
348 DirtyChanged (); /* EMIT SIGNAL */
352 } else if (state_was_pending) {
354 remove_pending_capture_state ();
355 state_was_pending = false;
362 Session::raid_path () const
364 Searchpath raid_search_path;
366 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
367 raid_search_path += (*i).path;
370 return raid_search_path.to_string ();
374 Session::setup_raid_path (string path)
383 session_dirs.clear ();
385 Searchpath search_path(path);
386 Searchpath sound_search_path;
387 Searchpath midi_search_path;
389 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
391 sp.blocks = 0; // not needed
392 session_dirs.push_back (sp);
394 SessionDirectory sdir(sp.path);
396 sound_search_path += sdir.sound_path ();
397 midi_search_path += sdir.midi_path ();
400 // reset the round-robin soundfile path thingie
401 last_rr_session_dir = session_dirs.begin();
405 Session::path_is_within_session (const std::string& path)
407 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
408 if (PBD::path_is_within (i->path, path)) {
416 Session::ensure_subdirs ()
420 dir = session_directory().peak_path();
422 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
423 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
427 dir = session_directory().sound_path();
429 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
430 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
434 dir = session_directory().midi_path();
436 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
437 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
441 dir = session_directory().dead_path();
443 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
444 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
448 dir = session_directory().export_path();
450 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
451 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
455 dir = analysis_dir ();
457 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
458 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
462 dir = plugins_dir ();
464 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
465 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
469 dir = externals_dir ();
471 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
472 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
479 /** @param session_template directory containing session template, or empty.
480 * Caller must not hold process lock.
483 Session::create (const string& session_template, BusProfile* bus_profile)
485 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
486 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
490 if (ensure_subdirs ()) {
494 _writable = exists_and_writable (_path);
496 if (!session_template.empty()) {
497 std::string in_path = session_template_dir_to_file (session_template);
499 ifstream in(in_path.c_str());
502 /* no need to call legalize_for_path() since the string
503 * in session_template is already a legal path name
505 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
507 ofstream out(out_path.c_str());
513 /* Copy plugin state files from template to new session */
514 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
515 copy_files (template_plugins, plugins_dir ());
520 error << string_compose (_("Could not open %1 for writing session template"), out_path)
526 error << string_compose (_("Could not open session template %1 for reading"), in_path)
533 /* set initial start + end point */
535 _state_of_the_state = Clean;
537 /* set up Master Out and Control Out if necessary */
542 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
544 if (bus_profile->master_out_channels) {
545 boost::shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
549 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
550 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
553 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
554 r->input()->ensure_io (count, false, this);
555 r->output()->ensure_io (count, false, this);
561 /* prohibit auto-connect to master, because there isn't one */
562 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
566 add_routes (rl, false, false, false);
569 /* this allows the user to override settings with an environment variable.
572 if (no_auto_connect()) {
573 bus_profile->input_ac = AutoConnectOption (0);
574 bus_profile->output_ac = AutoConnectOption (0);
577 Config->set_input_auto_connect (bus_profile->input_ac);
578 Config->set_output_auto_connect (bus_profile->output_ac);
581 if (Config->get_use_monitor_bus() && bus_profile) {
582 add_monitor_section ();
589 Session::maybe_write_autosave()
591 if (dirty() && record_status() != Recording) {
592 save_state("", true);
597 Session::remove_pending_capture_state ()
599 std::string pending_state_file_path(_session_dir->root_path());
601 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
603 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
605 if (g_remove (pending_state_file_path.c_str()) != 0) {
606 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
607 pending_state_file_path, g_strerror (errno)) << endmsg;
611 /** Rename a state file.
612 * @param old_name Old snapshot name.
613 * @param new_name New snapshot name.
616 Session::rename_state (string old_name, string new_name)
618 if (old_name == _current_snapshot_name || old_name == _name) {
619 /* refuse to rename the current snapshot or the "main" one */
623 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
624 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
626 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
627 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
629 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
630 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
631 old_name, new_name, g_strerror(errno)) << endmsg;
635 /** Remove a state file.
636 * @param snapshot_name Snapshot name.
639 Session::remove_state (string snapshot_name)
641 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
642 // refuse to remove the current snapshot or the "main" one
646 std::string xml_path(_session_dir->root_path());
648 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
650 if (!create_backup_file (xml_path)) {
651 // don't remove it if a backup can't be made
652 // create_backup_file will log the error.
657 if (g_remove (xml_path.c_str()) != 0) {
658 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
659 xml_path, g_strerror (errno)) << endmsg;
663 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
665 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
668 std::string xml_path(_session_dir->root_path());
670 if (!_writable || (_state_of_the_state & CannotSave)) {
674 if (!_engine.connected ()) {
675 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
681 /* tell sources we're saving first, in case they write out to a new file
682 * which should be saved with the state rather than the old one */
683 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
685 i->second->session_saved();
686 } catch (Evoral::SMF::FileError& e) {
687 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
691 SaveSession (); /* EMIT SIGNAL */
693 tree.set_root (&get_state());
695 if (snapshot_name.empty()) {
696 snapshot_name = _current_snapshot_name;
697 } else if (switch_to_snapshot) {
698 _current_snapshot_name = snapshot_name;
703 /* proper save: use statefile_suffix (.ardour in English) */
705 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
707 /* make a backup copy of the old file */
709 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
710 // create_backup_file will log the error
716 /* pending save: use pending_suffix (.pending in English) */
717 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
720 std::string tmp_path(_session_dir->root_path());
721 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
723 // cerr << "actually writing state to " << xml_path << endl;
725 if (!tree.write (tmp_path)) {
726 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
727 if (g_remove (tmp_path.c_str()) != 0) {
728 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
729 tmp_path, g_strerror (errno)) << endmsg;
735 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
736 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
737 tmp_path, xml_path, g_strerror(errno)) << endmsg;
738 if (g_remove (tmp_path.c_str()) != 0) {
739 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
740 tmp_path, g_strerror (errno)) << endmsg;
748 save_history (snapshot_name);
750 bool was_dirty = dirty();
752 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
755 DirtyChanged (); /* EMIT SIGNAL */
758 StateSaved (snapshot_name); /* EMIT SIGNAL */
765 Session::restore_state (string snapshot_name)
767 if (load_state (snapshot_name) == 0) {
768 set_state (*state_tree->root(), Stateful::loading_state_version);
775 Session::load_state (string snapshot_name)
780 state_was_pending = false;
782 /* check for leftover pending state from a crashed capture attempt */
784 std::string xmlpath(_session_dir->root_path());
785 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
787 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
789 /* there is pending state from a crashed capture attempt */
791 boost::optional<int> r = AskAboutPendingState();
792 if (r.get_value_or (1)) {
793 state_was_pending = true;
797 if (!state_was_pending) {
798 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
801 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
802 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
803 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
804 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
809 state_tree = new XMLTree;
813 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
815 if (!state_tree->read (xmlpath)) {
816 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
822 XMLNode& root (*state_tree->root());
824 if (root.name() != X_("Session")) {
825 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
831 const XMLProperty* prop;
833 if ((prop = root.property ("version")) == 0) {
834 /* no version implies very old version of Ardour */
835 Stateful::loading_state_version = 1000;
837 if (prop->value().find ('.') != string::npos) {
838 /* old school version format */
839 if (prop->value()[0] == '2') {
840 Stateful::loading_state_version = 2000;
842 Stateful::loading_state_version = 3000;
845 Stateful::loading_state_version = atoi (prop->value());
849 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
851 std::string backup_path(_session_dir->root_path());
852 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
853 backup_path = Glib::build_filename (backup_path, backup_filename);
855 // only create a backup for a given statefile version once
857 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
859 VersionMismatch (xmlpath, backup_path);
861 if (!copy_file (xmlpath, backup_path)) {;
871 Session::load_options (const XMLNode& node)
873 LocaleGuard lg (X_("POSIX"));
874 config.set_variables (node);
885 Session::get_template()
887 /* if we don't disable rec-enable, diskstreams
888 will believe they need to store their capture
889 sources in their state node.
892 disable_record (false);
898 Session::state (bool full_state)
900 XMLNode* node = new XMLNode("Session");
904 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
905 node->add_property("version", buf);
907 /* store configuration settings */
911 node->add_property ("name", _name);
912 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
913 node->add_property ("sample-rate", buf);
915 if (session_dirs.size() > 1) {
919 vector<space_and_path>::iterator i = session_dirs.begin();
920 vector<space_and_path>::iterator next;
922 ++i; /* skip the first one */
926 while (i != session_dirs.end()) {
930 if (next != session_dirs.end()) {
931 p += G_SEARCHPATH_SEPARATOR;
940 child = node->add_child ("Path");
941 child->add_content (p);
945 /* save the ID counter */
947 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
948 node->add_property ("id-counter", buf);
950 /* save the event ID counter */
952 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
953 node->add_property ("event-counter", buf);
955 /* various options */
957 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
958 if (!midi_port_nodes.empty()) {
959 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
960 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
961 midi_port_stuff->add_child_nocopy (**n);
963 node->add_child_nocopy (*midi_port_stuff);
966 node->add_child_nocopy (config.get_variables ());
968 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
970 child = node->add_child ("Sources");
973 Glib::Threads::Mutex::Lock sl (source_lock);
975 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
977 /* Don't save information about non-file Sources, or
978 * about non-destructive file sources that are empty
979 * and unused by any regions.
982 boost::shared_ptr<FileSource> fs;
984 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
986 if (!fs->destructive()) {
987 if (fs->empty() && !fs->used()) {
992 child->add_child_nocopy (siter->second->get_state());
997 child = node->add_child ("Regions");
1000 Glib::Threads::Mutex::Lock rl (region_lock);
1001 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1002 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1003 boost::shared_ptr<Region> r = i->second;
1004 /* only store regions not attached to playlists */
1005 if (r->playlist() == 0) {
1006 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1007 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1009 child->add_child_nocopy (r->get_state ());
1014 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1016 if (!cassocs.empty()) {
1017 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1019 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1021 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1022 i->first->id().print (buf, sizeof (buf));
1023 can->add_property (X_("copy"), buf);
1024 i->second->id().print (buf, sizeof (buf));
1025 can->add_property (X_("original"), buf);
1026 ca->add_child_nocopy (*can);
1032 node->add_child_nocopy (_locations->get_state());
1034 // for a template, just create a new Locations, populate it
1035 // with the default start and end, and get the state for that.
1036 Locations loc (*this);
1037 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1038 range->set (max_framepos, 0);
1040 node->add_child_nocopy (loc.get_state());
1043 child = node->add_child ("Bundles");
1045 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1046 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1047 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1049 child->add_child_nocopy (b->get_state());
1054 child = node->add_child ("Routes");
1056 boost::shared_ptr<RouteList> r = routes.reader ();
1058 RoutePublicOrderSorter cmp;
1059 RouteList public_order (*r);
1060 public_order.sort (cmp);
1062 /* the sort should have put control outs first */
1065 assert (_monitor_out == public_order.front());
1068 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1069 if (!(*i)->is_auditioner()) {
1071 child->add_child_nocopy ((*i)->get_state());
1073 child->add_child_nocopy ((*i)->get_template());
1079 playlists->add_state (node, full_state);
1081 child = node->add_child ("RouteGroups");
1082 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1083 child->add_child_nocopy ((*i)->get_state());
1087 XMLNode* gain_child = node->add_child ("Click");
1088 gain_child->add_child_nocopy (_click_io->state (full_state));
1089 gain_child->add_child_nocopy (_click_gain->state (full_state));
1093 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1094 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1098 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1099 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1102 node->add_child_nocopy (_speakers->get_state());
1103 node->add_child_nocopy (_tempo_map->get_state());
1104 node->add_child_nocopy (get_control_protocol_state());
1107 node->add_child_copy (*_extra_xml);
1114 Session::get_control_protocol_state ()
1116 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1117 return cpm.get_state();
1121 Session::set_state (const XMLNode& node, int version)
1125 const XMLProperty* prop;
1128 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1130 if (node.name() != X_("Session")) {
1131 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1135 if ((prop = node.property ("name")) != 0) {
1136 _name = prop->value ();
1139 if ((prop = node.property (X_("sample-rate"))) != 0) {
1141 _nominal_frame_rate = atoi (prop->value());
1143 if (_nominal_frame_rate != _current_frame_rate) {
1144 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1145 if (r.get_value_or (0)) {
1151 setup_raid_path(_session_dir->root_path());
1153 if ((prop = node.property (X_("id-counter"))) != 0) {
1155 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1156 ID::init_counter (x);
1158 /* old sessions used a timebased counter, so fake
1159 the startup ID counter based on a standard
1164 ID::init_counter (now);
1167 if ((prop = node.property (X_("event-counter"))) != 0) {
1168 Evoral::init_event_id_counter (atoi (prop->value()));
1172 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1173 _midi_ports->set_midi_port_states (child->children());
1176 IO::disable_connecting ();
1178 Stateful::save_extra_xml (node);
1180 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1181 load_options (*child);
1182 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1183 load_options (*child);
1185 error << _("Session: XML state has no options section") << endmsg;
1188 if (version >= 3000) {
1189 if ((child = find_named_node (node, "Metadata")) == 0) {
1190 warning << _("Session: XML state has no metadata section") << endmsg;
1191 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1196 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1197 _speakers->set_state (*child, version);
1200 if ((child = find_named_node (node, "Sources")) == 0) {
1201 error << _("Session: XML state has no sources section") << endmsg;
1203 } else if (load_sources (*child)) {
1207 if ((child = find_named_node (node, "TempoMap")) == 0) {
1208 error << _("Session: XML state has no Tempo Map section") << endmsg;
1210 } else if (_tempo_map->set_state (*child, version)) {
1214 if ((child = find_named_node (node, "Locations")) == 0) {
1215 error << _("Session: XML state has no locations section") << endmsg;
1217 } else if (_locations->set_state (*child, version)) {
1223 if ((location = _locations->auto_loop_location()) != 0) {
1224 set_auto_loop_location (location);
1227 if ((location = _locations->auto_punch_location()) != 0) {
1228 set_auto_punch_location (location);
1231 if ((location = _locations->session_range_location()) != 0) {
1232 delete _session_range_location;
1233 _session_range_location = location;
1236 if (_session_range_location) {
1237 AudioFileSource::set_header_position_offset (_session_range_location->start());
1240 if ((child = find_named_node (node, "Regions")) == 0) {
1241 error << _("Session: XML state has no Regions section") << endmsg;
1243 } else if (load_regions (*child)) {
1247 if ((child = find_named_node (node, "Playlists")) == 0) {
1248 error << _("Session: XML state has no playlists section") << endmsg;
1250 } else if (playlists->load (*this, *child)) {
1254 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1256 } else if (playlists->load_unused (*this, *child)) {
1260 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1261 if (load_compounds (*child)) {
1266 if (version >= 3000) {
1267 if ((child = find_named_node (node, "Bundles")) == 0) {
1268 warning << _("Session: XML state has no bundles section") << endmsg;
1271 /* We can't load Bundles yet as they need to be able
1272 to convert from port names to Port objects, which can't happen until
1274 _bundle_xml_node = new XMLNode (*child);
1278 if (version < 3000) {
1279 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1280 error << _("Session: XML state has no diskstreams section") << endmsg;
1282 } else if (load_diskstreams_2X (*child, version)) {
1287 if ((child = find_named_node (node, "Routes")) == 0) {
1288 error << _("Session: XML state has no routes section") << endmsg;
1290 } else if (load_routes (*child, version)) {
1294 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1295 _diskstreams_2X.clear ();
1297 if (version >= 3000) {
1299 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1300 error << _("Session: XML state has no route groups section") << endmsg;
1302 } else if (load_route_groups (*child, version)) {
1306 } else if (version < 3000) {
1308 if ((child = find_named_node (node, "EditGroups")) == 0) {
1309 error << _("Session: XML state has no edit groups section") << endmsg;
1311 } else if (load_route_groups (*child, version)) {
1315 if ((child = find_named_node (node, "MixGroups")) == 0) {
1316 error << _("Session: XML state has no mix groups section") << endmsg;
1318 } else if (load_route_groups (*child, version)) {
1323 if ((child = find_named_node (node, "Click")) == 0) {
1324 warning << _("Session: XML state has no click section") << endmsg;
1325 } else if (_click_io) {
1326 setup_click_state (&node);
1329 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1330 ControlProtocolManager::instance().set_state (*child, version);
1333 update_have_rec_enabled_track ();
1335 /* here beginneth the second phase ... */
1337 StateReady (); /* EMIT SIGNAL */
1346 Session::load_routes (const XMLNode& node, int version)
1349 XMLNodeConstIterator niter;
1350 RouteList new_routes;
1352 nlist = node.children();
1356 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1358 boost::shared_ptr<Route> route;
1359 if (version < 3000) {
1360 route = XMLRouteFactory_2X (**niter, version);
1362 route = XMLRouteFactory (**niter, version);
1366 error << _("Session: cannot create Route from XML description.") << endmsg;
1370 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1372 new_routes.push_back (route);
1375 add_routes (new_routes, false, false, false);
1380 boost::shared_ptr<Route>
1381 Session::XMLRouteFactory (const XMLNode& node, int version)
1383 boost::shared_ptr<Route> ret;
1385 if (node.name() != "Route") {
1389 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1391 DataType type = DataType::AUDIO;
1392 const XMLProperty* prop = node.property("default-type");
1395 type = DataType (prop->value());
1398 assert (type != DataType::NIL);
1402 boost::shared_ptr<Track> track;
1404 if (type == DataType::AUDIO) {
1405 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1407 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1410 if (track->init()) {
1414 if (track->set_state (node, version)) {
1418 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1419 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1424 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML")));
1426 if (r->init () == 0 && r->set_state (node, version) == 0) {
1427 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1428 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1437 boost::shared_ptr<Route>
1438 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1440 boost::shared_ptr<Route> ret;
1442 if (node.name() != "Route") {
1446 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1448 ds_prop = node.property (X_("diskstream"));
1451 DataType type = DataType::AUDIO;
1452 const XMLProperty* prop = node.property("default-type");
1455 type = DataType (prop->value());
1458 assert (type != DataType::NIL);
1462 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1463 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1467 if (i == _diskstreams_2X.end()) {
1468 error << _("Could not find diskstream for route") << endmsg;
1469 return boost::shared_ptr<Route> ();
1472 boost::shared_ptr<Track> track;
1474 if (type == DataType::AUDIO) {
1475 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1477 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1480 if (track->init()) {
1484 if (track->set_state (node, version)) {
1488 track->set_diskstream (*i);
1490 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1491 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1496 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML")));
1498 if (r->init () == 0 && r->set_state (node, version) == 0) {
1499 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1500 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1510 Session::load_regions (const XMLNode& node)
1513 XMLNodeConstIterator niter;
1514 boost::shared_ptr<Region> region;
1516 nlist = node.children();
1520 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1521 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1522 error << _("Session: cannot create Region from XML description.");
1523 const XMLProperty *name = (**niter).property("name");
1526 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1537 Session::load_compounds (const XMLNode& node)
1539 XMLNodeList calist = node.children();
1540 XMLNodeConstIterator caiter;
1541 XMLProperty *caprop;
1543 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1544 XMLNode* ca = *caiter;
1548 if ((caprop = ca->property (X_("original"))) == 0) {
1551 orig_id = caprop->value();
1553 if ((caprop = ca->property (X_("copy"))) == 0) {
1556 copy_id = caprop->value();
1558 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1559 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1561 if (!orig || !copy) {
1562 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1568 RegionFactory::add_compound_association (orig, copy);
1575 Session::load_nested_sources (const XMLNode& node)
1578 XMLNodeConstIterator niter;
1580 nlist = node.children();
1582 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1583 if ((*niter)->name() == "Source") {
1585 /* it may already exist, so don't recreate it unnecessarily
1588 XMLProperty* prop = (*niter)->property (X_("id"));
1590 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1594 ID source_id (prop->value());
1596 if (!source_by_id (source_id)) {
1599 SourceFactory::create (*this, **niter, true);
1601 catch (failed_constructor& err) {
1602 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1609 boost::shared_ptr<Region>
1610 Session::XMLRegionFactory (const XMLNode& node, bool full)
1612 const XMLProperty* type = node.property("type");
1616 const XMLNodeList& nlist = node.children();
1618 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1619 XMLNode *child = (*niter);
1620 if (child->name() == "NestedSource") {
1621 load_nested_sources (*child);
1625 if (!type || type->value() == "audio") {
1626 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1627 } else if (type->value() == "midi") {
1628 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1631 } catch (failed_constructor& err) {
1632 return boost::shared_ptr<Region> ();
1635 return boost::shared_ptr<Region> ();
1638 boost::shared_ptr<AudioRegion>
1639 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1641 const XMLProperty* prop;
1642 boost::shared_ptr<Source> source;
1643 boost::shared_ptr<AudioSource> as;
1645 SourceList master_sources;
1646 uint32_t nchans = 1;
1649 if (node.name() != X_("Region")) {
1650 return boost::shared_ptr<AudioRegion>();
1653 if ((prop = node.property (X_("channels"))) != 0) {
1654 nchans = atoi (prop->value().c_str());
1657 if ((prop = node.property ("name")) == 0) {
1658 cerr << "no name for this region\n";
1662 if ((prop = node.property (X_("source-0"))) == 0) {
1663 if ((prop = node.property ("source")) == 0) {
1664 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1665 return boost::shared_ptr<AudioRegion>();
1669 PBD::ID s_id (prop->value());
1671 if ((source = source_by_id (s_id)) == 0) {
1672 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1673 return boost::shared_ptr<AudioRegion>();
1676 as = boost::dynamic_pointer_cast<AudioSource>(source);
1678 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1679 return boost::shared_ptr<AudioRegion>();
1682 sources.push_back (as);
1684 /* pickup other channels */
1686 for (uint32_t n=1; n < nchans; ++n) {
1687 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1688 if ((prop = node.property (buf)) != 0) {
1690 PBD::ID id2 (prop->value());
1692 if ((source = source_by_id (id2)) == 0) {
1693 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1694 return boost::shared_ptr<AudioRegion>();
1697 as = boost::dynamic_pointer_cast<AudioSource>(source);
1699 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1700 return boost::shared_ptr<AudioRegion>();
1702 sources.push_back (as);
1706 for (uint32_t n = 0; n < nchans; ++n) {
1707 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1708 if ((prop = node.property (buf)) != 0) {
1710 PBD::ID id2 (prop->value());
1712 if ((source = source_by_id (id2)) == 0) {
1713 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1714 return boost::shared_ptr<AudioRegion>();
1717 as = boost::dynamic_pointer_cast<AudioSource>(source);
1719 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1720 return boost::shared_ptr<AudioRegion>();
1722 master_sources.push_back (as);
1727 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1729 /* a final detail: this is the one and only place that we know how long missing files are */
1731 if (region->whole_file()) {
1732 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1733 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1735 sfp->set_length (region->length());
1740 if (!master_sources.empty()) {
1741 if (master_sources.size() != nchans) {
1742 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1744 region->set_master_sources (master_sources);
1752 catch (failed_constructor& err) {
1753 return boost::shared_ptr<AudioRegion>();
1757 boost::shared_ptr<MidiRegion>
1758 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1760 const XMLProperty* prop;
1761 boost::shared_ptr<Source> source;
1762 boost::shared_ptr<MidiSource> ms;
1765 if (node.name() != X_("Region")) {
1766 return boost::shared_ptr<MidiRegion>();
1769 if ((prop = node.property ("name")) == 0) {
1770 cerr << "no name for this region\n";
1774 if ((prop = node.property (X_("source-0"))) == 0) {
1775 if ((prop = node.property ("source")) == 0) {
1776 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1777 return boost::shared_ptr<MidiRegion>();
1781 PBD::ID s_id (prop->value());
1783 if ((source = source_by_id (s_id)) == 0) {
1784 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1785 return boost::shared_ptr<MidiRegion>();
1788 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1790 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1791 return boost::shared_ptr<MidiRegion>();
1794 sources.push_back (ms);
1797 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1798 /* a final detail: this is the one and only place that we know how long missing files are */
1800 if (region->whole_file()) {
1801 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1802 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1804 sfp->set_length (region->length());
1812 catch (failed_constructor& err) {
1813 return boost::shared_ptr<MidiRegion>();
1818 Session::get_sources_as_xml ()
1821 XMLNode* node = new XMLNode (X_("Sources"));
1822 Glib::Threads::Mutex::Lock lm (source_lock);
1824 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1825 node->add_child_nocopy (i->second->get_state());
1832 Session::path_from_region_name (DataType type, string name, string identifier)
1834 char buf[PATH_MAX+1];
1836 SessionDirectory sdir(get_best_session_directory_for_new_source());
1837 std::string source_dir = ((type == DataType::AUDIO)
1838 ? sdir.sound_path() : sdir.midi_path());
1840 string ext = native_header_format_extension (config.get_native_file_header_format(), type);
1842 for (n = 0; n < 999999; ++n) {
1843 if (identifier.length()) {
1844 snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
1845 identifier.c_str(), n, ext.c_str());
1847 snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
1851 std::string source_path = Glib::build_filename (source_dir, buf);
1853 if (!Glib::file_test (source_path, Glib::FILE_TEST_EXISTS)) {
1858 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1867 Session::load_sources (const XMLNode& node)
1870 XMLNodeConstIterator niter;
1871 boost::shared_ptr<Source> source;
1873 nlist = node.children();
1877 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1880 if ((source = XMLSourceFactory (**niter)) == 0) {
1881 error << _("Session: cannot create Source from XML description.") << endmsg;
1884 } catch (MissingSource& err) {
1888 if (!no_questions_about_missing_files) {
1889 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1894 switch (user_choice) {
1896 /* user added a new search location, so try again */
1901 /* user asked to quit the entire session load
1906 no_questions_about_missing_files = true;
1910 no_questions_about_missing_files = true;
1915 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1916 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1925 boost::shared_ptr<Source>
1926 Session::XMLSourceFactory (const XMLNode& node)
1928 if (node.name() != "Source") {
1929 return boost::shared_ptr<Source>();
1933 /* note: do peak building in another thread when loading session state */
1934 return SourceFactory::create (*this, node, true);
1937 catch (failed_constructor& err) {
1938 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
1939 return boost::shared_ptr<Source>();
1944 Session::save_template (string template_name)
1948 if (_state_of_the_state & CannotSave) {
1952 std::string user_template_dir(user_template_directory());
1954 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
1955 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
1956 user_template_dir, g_strerror (errno)) << endmsg;
1960 tree.set_root (&get_template());
1962 std::string template_dir_path(user_template_dir);
1964 /* directory to put the template in */
1965 template_dir_path = Glib::build_filename (template_dir_path, template_name);
1967 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
1968 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
1969 template_dir_path) << endmsg;
1973 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
1974 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
1975 template_dir_path, g_strerror (errno)) << endmsg;
1980 std::string template_file_path(template_dir_path);
1981 template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
1983 if (!tree.write (template_file_path)) {
1984 error << _("template not saved") << endmsg;
1988 /* copy plugin state directory */
1990 std::string template_plugin_state_path(template_dir_path);
1991 template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
1993 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
1994 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
1995 template_plugin_state_path, g_strerror (errno)) << endmsg;
1999 copy_files (plugins_dir(), template_plugin_state_path);
2005 Session::refresh_disk_space ()
2007 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2009 Glib::Threads::Mutex::Lock lm (space_lock);
2011 /* get freespace on every FS that is part of the session path */
2013 _total_free_4k_blocks = 0;
2014 _total_free_4k_blocks_uncertain = false;
2016 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2018 struct statfs statfsbuf;
2019 statfs (i->path.c_str(), &statfsbuf);
2021 double const scale = statfsbuf.f_bsize / 4096.0;
2023 /* See if this filesystem is read-only */
2024 struct statvfs statvfsbuf;
2025 statvfs (i->path.c_str(), &statvfsbuf);
2027 /* f_bavail can be 0 if it is undefined for whatever
2028 filesystem we are looking at; Samba shares mounted
2029 via GVFS are an example of this.
2031 if (statfsbuf.f_bavail == 0) {
2032 /* block count unknown */
2034 i->blocks_unknown = true;
2035 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2036 /* read-only filesystem */
2038 i->blocks_unknown = false;
2040 /* read/write filesystem with known space */
2041 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2042 i->blocks_unknown = false;
2045 _total_free_4k_blocks += i->blocks;
2046 if (i->blocks_unknown) {
2047 _total_free_4k_blocks_uncertain = true;
2050 #elif defined (COMPILER_MSVC)
2051 vector<string> scanned_volumes;
2052 vector<string>::iterator j;
2053 vector<space_and_path>::iterator i;
2054 DWORD nSectorsPerCluster, nBytesPerSector,
2055 nFreeClusters, nTotalClusters;
2059 _total_free_4k_blocks = 0;
2061 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2062 strncpy (disk_drive, (*i).path.c_str(), 3);
2066 volume_found = false;
2067 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2069 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2070 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2071 i->blocks = (uint32_t)(nFreeBytes / 4096);
2073 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2074 if (0 == j->compare(disk_drive)) {
2075 volume_found = true;
2080 if (!volume_found) {
2081 scanned_volumes.push_back(disk_drive);
2082 _total_free_4k_blocks += i->blocks;
2087 if (0 == _total_free_4k_blocks) {
2088 strncpy (disk_drive, path().c_str(), 3);
2091 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2093 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2094 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2095 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2102 Session::get_best_session_directory_for_new_source ()
2104 vector<space_and_path>::iterator i;
2105 string result = _session_dir->root_path();
2107 /* handle common case without system calls */
2109 if (session_dirs.size() == 1) {
2113 /* OK, here's the algorithm we're following here:
2115 We want to select which directory to use for
2116 the next file source to be created. Ideally,
2117 we'd like to use a round-robin process so as to
2118 get maximum performance benefits from splitting
2119 the files across multiple disks.
2121 However, in situations without much diskspace, an
2122 RR approach may end up filling up a filesystem
2123 with new files while others still have space.
2124 Its therefore important to pay some attention to
2125 the freespace in the filesystem holding each
2126 directory as well. However, if we did that by
2127 itself, we'd keep creating new files in the file
2128 system with the most space until it was as full
2129 as all others, thus negating any performance
2130 benefits of this RAID-1 like approach.
2132 So, we use a user-configurable space threshold. If
2133 there are at least 2 filesystems with more than this
2134 much space available, we use RR selection between them.
2135 If not, then we pick the filesystem with the most space.
2137 This gets a good balance between the two
2141 refresh_disk_space ();
2143 int free_enough = 0;
2145 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2146 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2151 if (free_enough >= 2) {
2152 /* use RR selection process, ensuring that the one
2156 i = last_rr_session_dir;
2159 if (++i == session_dirs.end()) {
2160 i = session_dirs.begin();
2163 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2164 SessionDirectory sdir(i->path);
2165 if (sdir.create ()) {
2167 last_rr_session_dir = i;
2172 } while (i != last_rr_session_dir);
2176 /* pick FS with the most freespace (and that
2177 seems to actually work ...)
2180 vector<space_and_path> sorted;
2181 space_and_path_ascending_cmp cmp;
2183 sorted = session_dirs;
2184 sort (sorted.begin(), sorted.end(), cmp);
2186 for (i = sorted.begin(); i != sorted.end(); ++i) {
2187 SessionDirectory sdir(i->path);
2188 if (sdir.create ()) {
2190 last_rr_session_dir = i;
2200 Session::automation_dir () const
2202 return Glib::build_filename (_path, "automation");
2206 Session::analysis_dir () const
2208 return Glib::build_filename (_path, "analysis");
2212 Session::plugins_dir () const
2214 return Glib::build_filename (_path, "plugins");
2218 Session::externals_dir () const
2220 return Glib::build_filename (_path, "externals");
2224 Session::load_bundles (XMLNode const & node)
2226 XMLNodeList nlist = node.children();
2227 XMLNodeConstIterator niter;
2231 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2232 if ((*niter)->name() == "InputBundle") {
2233 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2234 } else if ((*niter)->name() == "OutputBundle") {
2235 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2237 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2246 Session::load_route_groups (const XMLNode& node, int version)
2248 XMLNodeList nlist = node.children();
2249 XMLNodeConstIterator niter;
2253 if (version >= 3000) {
2255 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2256 if ((*niter)->name() == "RouteGroup") {
2257 RouteGroup* rg = new RouteGroup (*this, "");
2258 add_route_group (rg);
2259 rg->set_state (**niter, version);
2263 } else if (version < 3000) {
2265 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2266 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2267 RouteGroup* rg = new RouteGroup (*this, "");
2268 add_route_group (rg);
2269 rg->set_state (**niter, version);
2278 Session::auto_save()
2280 save_state (_current_snapshot_name);
2284 state_file_filter (const string &str, void* /*arg*/)
2286 return (str.length() > strlen(statefile_suffix) &&
2287 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2291 bool operator()(const string* a, const string* b) {
2297 remove_end(string* state)
2299 string statename(*state);
2301 string::size_type start,end;
2302 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2303 statename = statename.substr (start+1);
2306 if ((end = statename.rfind(".ardour")) == string::npos) {
2307 end = statename.length();
2310 return new string(statename.substr (0, end));
2314 Session::possible_states (string path)
2316 PathScanner scanner;
2317 vector<string*>* states = scanner (path, state_file_filter, 0, false, false);
2319 transform(states->begin(), states->end(), states->begin(), remove_end);
2322 sort (states->begin(), states->end(), cmp);
2328 Session::possible_states () const
2330 return possible_states(_path);
2334 Session::add_route_group (RouteGroup* g)
2336 _route_groups.push_back (g);
2337 route_group_added (g); /* EMIT SIGNAL */
2339 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2340 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2341 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2347 Session::remove_route_group (RouteGroup& rg)
2349 list<RouteGroup*>::iterator i;
2351 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2352 _route_groups.erase (i);
2355 route_group_removed (); /* EMIT SIGNAL */
2359 /** Set a new order for our route groups, without adding or removing any.
2360 * @param groups Route group list in the new order.
2363 Session::reorder_route_groups (list<RouteGroup*> groups)
2365 _route_groups = groups;
2367 route_groups_reordered (); /* EMIT SIGNAL */
2373 Session::route_group_by_name (string name)
2375 list<RouteGroup *>::iterator i;
2377 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2378 if ((*i)->name() == name) {
2386 Session::all_route_group() const
2388 return *_all_route_group;
2392 Session::add_commands (vector<Command*> const & cmds)
2394 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2400 Session::begin_reversible_command (const string& name)
2402 begin_reversible_command (g_quark_from_string (name.c_str ()));
2405 /** Begin a reversible command using a GQuark to identify it.
2406 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2407 * but there must be as many begin...()s as there are commit...()s.
2410 Session::begin_reversible_command (GQuark q)
2412 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2413 to hold all the commands that are committed. This keeps the order of
2414 commands correct in the history.
2417 if (_current_trans == 0) {
2418 /* start a new transaction */
2419 assert (_current_trans_quarks.empty ());
2420 _current_trans = new UndoTransaction();
2421 _current_trans->set_name (g_quark_to_string (q));
2424 _current_trans_quarks.push_front (q);
2428 Session::commit_reversible_command (Command *cmd)
2430 assert (_current_trans);
2431 assert (!_current_trans_quarks.empty ());
2436 _current_trans->add_command (cmd);
2439 _current_trans_quarks.pop_front ();
2441 if (!_current_trans_quarks.empty ()) {
2442 /* the transaction we're committing is not the top-level one */
2446 if (_current_trans->empty()) {
2447 /* no commands were added to the transaction, so just get rid of it */
2448 delete _current_trans;
2453 gettimeofday (&now, 0);
2454 _current_trans->set_timestamp (now);
2456 _history.add (_current_trans);
2461 accept_all_audio_files (const string& path, void* /*arg*/)
2463 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2467 if (!AudioFileSource::safe_audio_file_extension (path)) {
2475 accept_all_midi_files (const string& path, void* /*arg*/)
2477 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2481 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2482 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2483 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2487 accept_all_state_files (const string& path, void* /*arg*/)
2489 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2493 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2497 Session::find_all_sources (string path, set<string>& result)
2502 if (!tree.read (path)) {
2506 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2511 XMLNodeConstIterator niter;
2513 nlist = node->children();
2517 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2521 if ((prop = (*niter)->property (X_("type"))) == 0) {
2525 DataType type (prop->value());
2527 if ((prop = (*niter)->property (X_("name"))) == 0) {
2531 if (Glib::path_is_absolute (prop->value())) {
2532 /* external file, ignore */
2540 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2541 result.insert (found_path);
2549 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2551 PathScanner scanner;
2552 vector<string*>* state_files;
2554 string this_snapshot_path;
2560 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2561 ripped = ripped.substr (0, ripped.length() - 1);
2564 state_files = scanner (ripped, accept_all_state_files, (void *) 0, true, true);
2566 if (state_files == 0) {
2571 this_snapshot_path = _path;
2572 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2573 this_snapshot_path += statefile_suffix;
2575 for (vector<string*>::iterator i = state_files->begin(); i != state_files->end(); ++i) {
2577 if (exclude_this_snapshot && **i == this_snapshot_path) {
2581 if (find_all_sources (**i, result) < 0) {
2589 struct RegionCounter {
2590 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2591 AudioSourceList::iterator iter;
2592 boost::shared_ptr<Region> region;
2595 RegionCounter() : count (0) {}
2599 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2601 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2602 return r.get_value_or (1);
2606 Session::cleanup_regions ()
2608 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2610 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2612 uint32_t used = playlists->region_use_count (i->second);
2614 if (used == 0 && !i->second->automatic ()) {
2615 RegionFactory::map_remove (i->second);
2619 /* dump the history list */
2626 Session::cleanup_sources (CleanupReport& rep)
2628 // FIXME: needs adaptation to midi
2630 vector<boost::shared_ptr<Source> > dead_sources;
2631 PathScanner scanner;
2634 vector<space_and_path>::iterator i;
2635 vector<space_and_path>::iterator nexti;
2636 vector<string*>* candidates;
2637 vector<string*>* candidates2;
2638 vector<string> unused;
2639 set<string> all_sources;
2646 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2648 /* consider deleting all unused playlists */
2650 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2655 /* sync the "all regions" property of each playlist with its current state
2658 playlists->sync_all_regions_with_regions ();
2660 /* find all un-used sources */
2665 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2667 SourceMap::iterator tmp;
2672 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2676 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2677 dead_sources.push_back (i->second);
2678 i->second->drop_references ();
2684 /* build a list of all the possible audio directories for the session */
2686 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2691 SessionDirectory sdir ((*i).path);
2692 audio_path += sdir.sound_path();
2694 if (nexti != session_dirs.end()) {
2695 audio_path += G_SEARCHPATH_SEPARATOR;
2702 /* build a list of all the possible midi directories for the session */
2704 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2709 SessionDirectory sdir ((*i).path);
2710 midi_path += sdir.midi_path();
2712 if (nexti != session_dirs.end()) {
2713 midi_path += G_SEARCHPATH_SEPARATOR;
2719 candidates = scanner (audio_path, accept_all_audio_files, (void *) 0, true, true);
2720 candidates2 = scanner (midi_path, accept_all_midi_files, (void *) 0, true, true);
2726 for (vector<string*>::iterator i = candidates2->begin(); i != candidates2->end(); ++i) {
2727 candidates->push_back (*i);
2732 candidates = candidates2; // might still be null
2735 /* find all sources, but don't use this snapshot because the
2736 state file on disk still references sources we may have already
2740 find_all_sources_across_snapshots (all_sources, true);
2742 /* add our current source list
2745 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2746 boost::shared_ptr<FileSource> fs;
2747 SourceMap::iterator tmp = i;
2750 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2752 if (!fs->is_stub()) {
2754 if (playlists->source_use_count (fs) != 0) {
2755 all_sources.insert (fs->path());
2758 /* we might not remove this source from disk, because it may be used
2759 by other snapshots, but its not being used in this version
2760 so lets get rid of it now, along with any representative regions
2764 RegionFactory::remove_regions_using_source (i->second);
2774 for (vector<string*>::iterator x = candidates->begin(); x != candidates->end(); ++x) {
2779 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2781 tmppath1 = canonical_path (spath);
2782 tmppath2 = canonical_path ((*i));
2784 if (tmppath1 == tmppath2) {
2791 unused.push_back (spath);
2800 /* now try to move all unused files into the "dead" directory(ies) */
2802 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2803 struct stat statbuf;
2807 /* don't move the file across filesystems, just
2808 stick it in the `dead_dir_name' directory
2809 on whichever filesystem it was already on.
2812 if ((*x).find ("/sounds/") != string::npos) {
2814 /* old school, go up 1 level */
2816 newpath = Glib::path_get_dirname (*x); // "sounds"
2817 newpath = Glib::path_get_dirname (newpath); // "session-name"
2821 /* new school, go up 4 levels */
2823 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2824 newpath = Glib::path_get_dirname (newpath); // "session-name"
2825 newpath = Glib::path_get_dirname (newpath); // "interchange"
2826 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2829 newpath = Glib::build_filename (newpath, dead_dir_name);
2831 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2832 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2836 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2838 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2840 /* the new path already exists, try versioning */
2842 char buf[PATH_MAX+1];
2846 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2849 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2850 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2854 if (version == 999) {
2855 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2859 newpath = newpath_v;
2864 /* it doesn't exist, or we can't read it or something */
2868 stat ((*x).c_str(), &statbuf);
2870 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2871 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2872 (*x), newpath, strerror (errno))
2877 /* see if there an easy to find peakfile for this file, and remove it.
2880 string base = basename_nosuffix (*x);
2881 base += "%A"; /* this is what we add for the channel suffix of all native files,
2882 or for the first channel of embedded files. it will miss
2883 some peakfiles for other channels
2885 string peakpath = peak_path (base);
2887 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2888 if (::g_unlink (peakpath.c_str()) != 0) {
2889 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2890 peakpath, _path, strerror (errno))
2892 /* try to back out */
2893 ::rename (newpath.c_str(), _path.c_str());
2898 rep.paths.push_back (*x);
2899 rep.space += statbuf.st_size;
2902 /* dump the history list */
2906 /* save state so we don't end up a session file
2907 referring to non-existent sources.
2914 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2920 Session::cleanup_trash_sources (CleanupReport& rep)
2922 // FIXME: needs adaptation for MIDI
2924 vector<space_and_path>::iterator i;
2930 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2932 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2934 clear_directory (dead_dir, &rep.space, &rep.paths);
2941 Session::set_dirty ()
2943 bool was_dirty = dirty();
2945 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2949 DirtyChanged(); /* EMIT SIGNAL */
2955 Session::set_clean ()
2957 bool was_dirty = dirty();
2959 _state_of_the_state = Clean;
2963 DirtyChanged(); /* EMIT SIGNAL */
2968 Session::set_deletion_in_progress ()
2970 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2974 Session::clear_deletion_in_progress ()
2976 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2980 Session::add_controllable (boost::shared_ptr<Controllable> c)
2982 /* this adds a controllable to the list managed by the Session.
2983 this is a subset of those managed by the Controllable class
2984 itself, and represents the only ones whose state will be saved
2985 as part of the session.
2988 Glib::Threads::Mutex::Lock lm (controllables_lock);
2989 controllables.insert (c);
2992 struct null_deleter { void operator()(void const *) const {} };
2995 Session::remove_controllable (Controllable* c)
2997 if (_state_of_the_state & Deletion) {
3001 Glib::Threads::Mutex::Lock lm (controllables_lock);
3003 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3005 if (x != controllables.end()) {
3006 controllables.erase (x);
3010 boost::shared_ptr<Controllable>
3011 Session::controllable_by_id (const PBD::ID& id)
3013 Glib::Threads::Mutex::Lock lm (controllables_lock);
3015 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3016 if ((*i)->id() == id) {
3021 return boost::shared_ptr<Controllable>();
3024 boost::shared_ptr<Controllable>
3025 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3027 boost::shared_ptr<Controllable> c;
3028 boost::shared_ptr<Route> r;
3030 switch (desc.top_level_type()) {
3031 case ControllableDescriptor::NamedRoute:
3033 std::string str = desc.top_level_name();
3034 if (str == "master") {
3036 } else if (str == "control" || str == "listen") {
3039 r = route_by_name (desc.top_level_name());
3044 case ControllableDescriptor::RemoteControlID:
3045 r = route_by_remote_id (desc.rid());
3053 switch (desc.subtype()) {
3054 case ControllableDescriptor::Gain:
3055 c = r->gain_control ();
3058 case ControllableDescriptor::Solo:
3059 c = r->solo_control();
3062 case ControllableDescriptor::Mute:
3063 c = r->mute_control();
3066 case ControllableDescriptor::Recenable:
3068 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3071 c = t->rec_enable_control ();
3076 case ControllableDescriptor::PanDirection:
3078 c = r->pannable()->pan_azimuth_control;
3082 case ControllableDescriptor::PanWidth:
3084 c = r->pannable()->pan_width_control;
3088 case ControllableDescriptor::PanElevation:
3090 c = r->pannable()->pan_elevation_control;
3094 case ControllableDescriptor::Balance:
3095 /* XXX simple pan control */
3098 case ControllableDescriptor::PluginParameter:
3100 uint32_t plugin = desc.target (0);
3101 uint32_t parameter_index = desc.target (1);
3103 /* revert to zero based counting */
3109 if (parameter_index > 0) {
3113 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3116 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3117 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3122 case ControllableDescriptor::SendGain:
3124 uint32_t send = desc.target (0);
3126 /* revert to zero-based counting */
3132 boost::shared_ptr<Processor> p = r->nth_send (send);
3135 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3136 boost::shared_ptr<Amp> a = s->amp();
3139 c = s->amp()->gain_control();
3146 /* relax and return a null pointer */
3154 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3157 Stateful::add_instant_xml (node, _path);
3160 if (write_to_config) {
3161 Config->add_instant_xml (node);
3166 Session::instant_xml (const string& node_name)
3168 return Stateful::instant_xml (node_name, _path);
3172 Session::save_history (string snapshot_name)
3180 if (snapshot_name.empty()) {
3181 snapshot_name = _current_snapshot_name;
3184 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3185 const string backup_filename = history_filename + backup_suffix;
3186 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3187 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3189 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3190 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3191 error << _("could not backup old history file, current history not saved") << endmsg;
3196 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
3200 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3202 if (!tree.write (xml_path))
3204 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3206 if (g_remove (xml_path.c_str()) != 0) {
3207 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3208 xml_path, g_strerror (errno)) << endmsg;
3210 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3211 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3212 backup_path, g_strerror (errno)) << endmsg;
3222 Session::restore_history (string snapshot_name)
3226 if (snapshot_name.empty()) {
3227 snapshot_name = _current_snapshot_name;
3230 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3231 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3233 info << "Loading history from " << xml_path << endmsg;
3235 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3236 info << string_compose (_("%1: no history file \"%2\" for this session."),
3237 _name, xml_path) << endmsg;
3241 if (!tree.read (xml_path)) {
3242 error << string_compose (_("Could not understand session history file \"%1\""),
3243 xml_path) << endmsg;
3250 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3253 UndoTransaction* ut = new UndoTransaction ();
3256 ut->set_name(t->property("name")->value());
3257 stringstream ss(t->property("tv-sec")->value());
3259 ss.str(t->property("tv-usec")->value());
3261 ut->set_timestamp(tv);
3263 for (XMLNodeConstIterator child_it = t->children().begin();
3264 child_it != t->children().end(); child_it++)
3266 XMLNode *n = *child_it;
3269 if (n->name() == "MementoCommand" ||
3270 n->name() == "MementoUndoCommand" ||
3271 n->name() == "MementoRedoCommand") {
3273 if ((c = memento_command_factory(n))) {
3277 } else if (n->name() == "NoteDiffCommand") {
3278 PBD::ID id (n->property("midi-source")->value());
3279 boost::shared_ptr<MidiSource> midi_source =
3280 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3282 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3284 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3287 } else if (n->name() == "SysExDiffCommand") {
3289 PBD::ID id (n->property("midi-source")->value());
3290 boost::shared_ptr<MidiSource> midi_source =
3291 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3293 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3295 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3298 } else if (n->name() == "PatchChangeDiffCommand") {
3300 PBD::ID id (n->property("midi-source")->value());
3301 boost::shared_ptr<MidiSource> midi_source =
3302 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3304 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3306 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3309 } else if (n->name() == "StatefulDiffCommand") {
3310 if ((c = stateful_diff_command_factory (n))) {
3311 ut->add_command (c);
3314 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3325 Session::config_changed (std::string p, bool ours)
3331 if (p == "seamless-loop") {
3333 } else if (p == "rf-speed") {
3335 } else if (p == "auto-loop") {
3337 } else if (p == "auto-input") {
3339 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3340 /* auto-input only makes a difference if we're rolling */
3341 set_track_monitor_input_status (!config.get_auto_input());
3344 } else if (p == "punch-in") {
3348 if ((location = _locations->auto_punch_location()) != 0) {
3350 if (config.get_punch_in ()) {
3351 replace_event (SessionEvent::PunchIn, location->start());
3353 remove_event (location->start(), SessionEvent::PunchIn);
3357 } else if (p == "punch-out") {
3361 if ((location = _locations->auto_punch_location()) != 0) {
3363 if (config.get_punch_out()) {
3364 replace_event (SessionEvent::PunchOut, location->end());
3366 clear_events (SessionEvent::PunchOut);
3370 } else if (p == "edit-mode") {
3372 Glib::Threads::Mutex::Lock lm (playlists->lock);
3374 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3375 (*i)->set_edit_mode (Config->get_edit_mode ());
3378 } else if (p == "use-video-sync") {
3380 waiting_for_sync_offset = config.get_use_video_sync();
3382 } else if (p == "mmc-control") {
3384 //poke_midi_thread ();
3386 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3388 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3390 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3392 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3394 } else if (p == "midi-control") {
3396 //poke_midi_thread ();
3398 } else if (p == "raid-path") {
3400 setup_raid_path (config.get_raid_path());
3402 } else if (p == "timecode-format") {
3406 } else if (p == "video-pullup") {
3410 } else if (p == "seamless-loop") {
3412 if (play_loop && transport_rolling()) {
3413 // to reset diskstreams etc
3414 request_play_loop (true);
3417 } else if (p == "rf-speed") {
3419 cumulative_rf_motion = 0;
3422 } else if (p == "click-sound") {
3424 setup_click_sounds (1);
3426 } else if (p == "click-emphasis-sound") {
3428 setup_click_sounds (-1);
3430 } else if (p == "clicking") {
3432 if (Config->get_clicking()) {
3433 if (_click_io && click_data) { // don't require emphasis data
3440 } else if (p == "click-gain") {
3443 _click_gain->set_gain (Config->get_click_gain(), this);
3446 } else if (p == "send-mtc") {
3448 if (Config->get_send_mtc ()) {
3449 /* mark us ready to send */
3450 next_quarter_frame_to_send = 0;
3453 } else if (p == "send-mmc") {
3455 _mmc->enable_send (Config->get_send_mmc ());
3457 } else if (p == "midi-feedback") {
3459 session_midi_feedback = Config->get_midi_feedback();
3461 } else if (p == "jack-time-master") {
3463 engine().reset_timebase ();
3465 } else if (p == "native-file-header-format") {
3467 if (!first_file_header_format_reset) {
3468 reset_native_file_format ();
3471 first_file_header_format_reset = false;
3473 } else if (p == "native-file-data-format") {
3475 if (!first_file_data_format_reset) {
3476 reset_native_file_format ();
3479 first_file_data_format_reset = false;
3481 } else if (p == "external-sync") {
3482 if (!config.get_external_sync()) {
3483 drop_sync_source ();
3485 switch_to_sync_source (Config->get_sync_source());
3487 } else if (p == "denormal-model") {
3489 } else if (p == "history-depth") {
3490 set_history_depth (Config->get_history_depth());
3491 } else if (p == "remote-model") {
3492 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3495 } else if (p == "initial-program-change") {
3497 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3500 buf[0] = MIDI::program; // channel zero by default
3501 buf[1] = (Config->get_initial_program_change() & 0x7f);
3503 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3505 } else if (p == "solo-mute-override") {
3506 // catch_up_on_solo_mute_override ();
3507 } else if (p == "listen-position" || p == "pfl-position") {
3508 listen_position_changed ();
3509 } else if (p == "solo-control-is-listen-control") {
3510 solo_control_mode_changed ();
3511 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3512 last_timecode_valid = false;
3513 } else if (p == "playback-buffer-seconds") {
3514 AudioSource::allocate_working_buffers (frame_rate());
3515 } else if (p == "automation-thinning-factor") {
3516 Evoral::ControlList::set_thinning_factor (Config->get_automation_thinning_factor());
3517 } else if (p == "ltc-source-port") {
3518 reconnect_ltc_input ();
3519 } else if (p == "ltc-sink-port") {
3520 reconnect_ltc_output ();
3521 } else if (p == "timecode-generator-offset") {
3522 ltc_tx_parse_offset();
3529 Session::set_history_depth (uint32_t d)
3531 _history.set_depth (d);
3535 Session::load_diskstreams_2X (XMLNode const & node, int)
3538 XMLNodeConstIterator citer;
3540 clist = node.children();
3542 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3545 /* diskstreams added automatically by DiskstreamCreated handler */
3546 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3547 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3548 _diskstreams_2X.push_back (dsp);
3550 error << _("Session: unknown diskstream type in XML") << endmsg;
3554 catch (failed_constructor& err) {
3555 error << _("Session: could not load diskstream via XML state") << endmsg;
3563 /** Connect things to the MMC object */
3565 Session::setup_midi_machine_control ()
3567 _mmc = new MIDI::MachineControl;
3568 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3570 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3571 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3572 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3573 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3574 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3575 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3576 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3577 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3578 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3579 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3580 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3581 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3582 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3584 /* also handle MIDI SPP because its so common */
3586 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3587 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3588 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3591 boost::shared_ptr<Controllable>
3592 Session::solo_cut_control() const
3594 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3595 controls in Ardour that currently get presented to the user in the GUI that require
3596 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3598 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3599 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3603 return _solo_cut_control;
3607 Session::rename (const std::string& new_name)
3609 string legal_name = legalize_for_path (new_name);
3615 string const old_sources_root = _session_dir->sources_root();
3620 * interchange subdirectory
3624 * Backup files are left unchanged and not renamed.
3627 /* pass one: not 100% safe check that the new directory names don't
3631 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3636 /* this is a stupid hack because Glib::path_get_dirname() is
3637 * lexical-only, and so passing it /a/b/c/ gives a different
3638 * result than passing it /a/b/c ...
3641 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3642 oldstr = oldstr.substr (0, oldstr.length() - 1);
3645 string base = Glib::path_get_dirname (oldstr);
3646 string p = Glib::path_get_basename (oldstr);
3648 newstr = Glib::build_filename (base, legal_name);
3650 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3657 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3662 /* this is a stupid hack because Glib::path_get_dirname() is
3663 * lexical-only, and so passing it /a/b/c/ gives a different
3664 * result than passing it /a/b/c ...
3667 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3668 oldstr = oldstr.substr (0, oldstr.length() - 1);
3671 string base = Glib::path_get_dirname (oldstr);
3672 string p = Glib::path_get_basename (oldstr);
3674 newstr = Glib::build_filename (base, legal_name);
3676 cerr << "Rename " << oldstr << " => " << newstr << endl;
3678 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3679 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3684 (*_session_dir) = newstr;
3689 /* directory below interchange */
3691 v.push_back (newstr);
3692 v.push_back (interchange_dir_name);
3695 oldstr = Glib::build_filename (v);
3698 v.push_back (newstr);
3699 v.push_back (interchange_dir_name);
3700 v.push_back (legal_name);
3702 newstr = Glib::build_filename (v);
3704 cerr << "Rename " << oldstr << " => " << newstr << endl;
3706 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3707 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3714 oldstr = Glib::build_filename (newpath, _current_snapshot_name) + statefile_suffix;
3715 newstr= Glib::build_filename (newpath, legal_name) + statefile_suffix;
3717 cerr << "Rename " << oldstr << " => " << newstr << endl;
3719 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3720 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3727 oldstr = Glib::build_filename (newpath, _current_snapshot_name) + history_suffix;
3729 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3730 newstr = Glib::build_filename (newpath, legal_name) + history_suffix;
3732 cerr << "Rename " << oldstr << " => " << newstr << endl;
3734 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3735 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3740 /* update file source paths */
3742 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3743 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3745 string p = fs->path ();
3746 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3751 /* remove old name from recent sessions */
3753 remove_recent_sessions (_path);
3756 _current_snapshot_name = new_name;
3759 /* re-add directory separator - reverse hack to oldstr above */
3760 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
3761 _path += G_DIR_SEPARATOR;
3766 /* save state again to get everything just right */
3768 save_state (_current_snapshot_name);
3771 /* add to recent sessions */
3773 store_recent_sessions (new_name, _path);
3779 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3781 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3785 if (!tree.read (xmlpath)) {
3793 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3796 bool found_sr = false;
3797 bool found_data_format = false;
3799 if (get_session_info_from_path (tree, xmlpath)) {
3805 const XMLProperty* prop;
3806 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3807 sample_rate = atoi (prop->value());
3811 const XMLNodeList& children (tree.root()->children());
3812 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3813 const XMLNode* child = *c;
3814 if (child->name() == "Config") {
3815 const XMLNodeList& options (child->children());
3816 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3817 const XMLNode* option = *oc;
3818 const XMLProperty* name = option->property("name");
3824 if (name->value() == "native-file-data-format") {
3825 const XMLProperty* value = option->property ("value");
3827 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3829 found_data_format = true;
3835 if (found_data_format) {
3840 return !(found_sr && found_data_format); // zero if they are both found