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/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/clear_dir.h"
76 #include "pbd/localtime_r.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/port.h"
101 #include "ardour/processor.h"
102 #include "ardour/proxy_controllable.h"
103 #include "ardour/recent_sessions.h"
104 #include "ardour/region_factory.h"
105 #include "ardour/route_group.h"
106 #include "ardour/send.h"
107 #include "ardour/session.h"
108 #include "ardour/session_directory.h"
109 #include "ardour/session_metadata.h"
110 #include "ardour/session_playlists.h"
111 #include "ardour/session_state_utils.h"
112 #include "ardour/silentfilesource.h"
113 #include "ardour/sndfilesource.h"
114 #include "ardour/source_factory.h"
115 #include "ardour/speakers.h"
116 #include "ardour/template_utils.h"
117 #include "ardour/tempo.h"
118 #include "ardour/ticker.h"
119 #include "ardour/user_bundle.h"
121 #include "control_protocol/control_protocol.h"
127 using namespace ARDOUR;
131 Session::pre_engine_init (string fullpath)
133 if (fullpath.empty()) {
135 throw failed_constructor();
138 /* discover canonical fullpath */
140 _path = canonical_path(fullpath);
142 /* we require _path to end with a dir separator */
144 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
145 _path += G_DIR_SEPARATOR;
150 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
152 /* finish initialization that can't be done in a normal C++ constructor
156 timerclear (&last_mmc_step);
157 g_atomic_int_set (&processing_prohibited, 0);
158 g_atomic_int_set (&_record_status, Disabled);
159 g_atomic_int_set (&_playback_load, 100);
160 g_atomic_int_set (&_capture_load, 100);
162 _all_route_group->set_active (true, this);
163 interpolation.add_channel_to (0, 0);
165 if (config.get_use_video_sync()) {
166 waiting_for_sync_offset = true;
168 waiting_for_sync_offset = false;
171 last_rr_session_dir = session_dirs.begin();
173 set_history_depth (Config->get_history_depth());
175 /* default: assume simple stereo speaker configuration */
177 _speakers->setup_default_speakers (2);
179 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
180 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
181 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
182 add_controllable (_solo_cut_control);
184 /* These are all static "per-class" signals */
186 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
187 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
188 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
189 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
190 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
192 /* stop IO objects from doing stuff until we're ready for them */
194 Delivery::disable_panners ();
195 IO::disable_connecting ();
197 AudioFileSource::set_peak_dir (_session_dir->peak_path());
201 Session::post_engine_init ()
203 BootMessage (_("Set block size and sample rate"));
205 set_block_size (_engine.samples_per_cycle());
206 set_frame_rate (_engine.sample_rate());
208 BootMessage (_("Using configuration"));
210 _midi_ports = new MidiPortManager;
212 MIDISceneChanger* msc;
214 _scene_changer = msc = new MIDISceneChanger (*this);
215 msc->set_input_port (scene_input_port());
216 msc->set_output_port (scene_out());
218 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
219 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
221 setup_midi_machine_control ();
223 if (_butler->start_thread()) {
227 if (start_midi_thread ()) {
231 setup_click_sounds (0);
232 setup_midi_control ();
234 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
235 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
238 /* tempo map requires sample rate knowledge */
240 _tempo_map = new TempoMap (_current_frame_rate);
241 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
243 /* MidiClock requires a tempo map */
245 midi_clock = new MidiClockTicker ();
246 midi_clock->set_session (this);
248 /* crossfades require sample rate knowledge */
250 SndFileSource::setup_standard_crossfades (*this, frame_rate());
251 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
253 AudioDiskstream::allocate_working_buffers();
254 refresh_disk_space ();
256 /* we're finally ready to call set_state() ... all objects have
257 * been created, the engine is running.
261 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
265 // set_state() will call setup_raid_path(), but if it's a new session we need
266 // to call setup_raid_path() here.
267 setup_raid_path (_path);
272 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
273 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
275 Config->map_parameters (ff);
276 config.map_parameters (ft);
278 /* Reset all panners */
280 Delivery::reset_panners ();
282 /* this will cause the CPM to instantiate any protocols that are in use
283 * (or mandatory), which will pass it this Session, and then call
284 * set_state() on each instantiated protocol to match stored state.
287 ControlProtocolManager::instance().set_session (this);
289 /* This must be done after the ControlProtocolManager set_session above,
290 as it will set states for ports which the ControlProtocolManager creates.
293 // XXX set state of MIDI::Port's
294 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
296 /* And this must be done after the MIDI::Manager::set_port_states as
297 * it will try to make connections whose details are loaded by set_port_states.
302 /* Let control protocols know that we are now all connected, so they
303 * could start talking to surfaces if they want to.
306 ControlProtocolManager::instance().midi_connectivity_established ();
308 if (_is_new && !no_auto_connect()) {
309 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
310 auto_connect_master_bus ();
313 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
315 /* update latencies */
317 initialize_latencies ();
319 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
320 _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
322 } catch (AudioEngine::PortRegistrationFailure& err) {
323 /* handle this one in a different way than all others, so that its clear what happened */
324 error << err.what() << endmsg;
330 BootMessage (_("Reset Remote Controls"));
332 // send_full_time_code (0);
333 _engine.transport_locate (0);
335 _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
336 _mmc->send (MIDI::MachineControlCommand (Timecode::Time ()));
338 MIDI::Name::MidiPatchManager::instance().set_session (this);
341 /* initial program change will be delivered later; see ::config_changed() */
343 _state_of_the_state = Clean;
345 Port::set_connecting_blocked (false);
347 DirtyChanged (); /* EMIT SIGNAL */
351 } else if (state_was_pending) {
353 remove_pending_capture_state ();
354 state_was_pending = false;
361 Session::raid_path () const
363 Searchpath raid_search_path;
365 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
366 raid_search_path += (*i).path;
369 return raid_search_path.to_string ();
373 Session::setup_raid_path (string path)
382 session_dirs.clear ();
384 Searchpath search_path(path);
385 Searchpath sound_search_path;
386 Searchpath midi_search_path;
388 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
390 sp.blocks = 0; // not needed
391 session_dirs.push_back (sp);
393 SessionDirectory sdir(sp.path);
395 sound_search_path += sdir.sound_path ();
396 midi_search_path += sdir.midi_path ();
399 // reset the round-robin soundfile path thingie
400 last_rr_session_dir = session_dirs.begin();
404 Session::path_is_within_session (const std::string& path)
406 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
407 if (PBD::path_is_within (i->path, path)) {
415 Session::ensure_subdirs ()
419 dir = session_directory().peak_path();
421 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
422 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
426 dir = session_directory().sound_path();
428 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
429 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
433 dir = session_directory().midi_path();
435 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
436 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
440 dir = session_directory().dead_path();
442 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
443 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
447 dir = session_directory().export_path();
449 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
450 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
454 dir = analysis_dir ();
456 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
457 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
461 dir = plugins_dir ();
463 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
464 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
468 dir = externals_dir ();
470 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
471 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
478 /** @param session_template directory containing session template, or empty.
479 * Caller must not hold process lock.
482 Session::create (const string& session_template, BusProfile* bus_profile)
484 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
489 if (ensure_subdirs ()) {
493 _writable = exists_and_writable (_path);
495 if (!session_template.empty()) {
496 std::string in_path = session_template_dir_to_file (session_template);
498 ifstream in(in_path.c_str());
501 /* no need to call legalize_for_path() since the string
502 * in session_template is already a legal path name
504 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
506 ofstream out(out_path.c_str());
512 /* Copy plugin state files from template to new session */
513 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
514 copy_files (template_plugins, plugins_dir ());
519 error << string_compose (_("Could not open %1 for writing session template"), out_path)
525 error << string_compose (_("Could not open session template %1 for reading"), in_path)
532 /* set initial start + end point */
534 _state_of_the_state = Clean;
536 /* set up Master Out and Control Out if necessary */
541 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
543 if (bus_profile->master_out_channels) {
544 boost::shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
548 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
549 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
552 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
553 r->input()->ensure_io (count, false, this);
554 r->output()->ensure_io (count, false, this);
560 /* prohibit auto-connect to master, because there isn't one */
561 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
565 add_routes (rl, false, false, false);
568 /* this allows the user to override settings with an environment variable.
571 if (no_auto_connect()) {
572 bus_profile->input_ac = AutoConnectOption (0);
573 bus_profile->output_ac = AutoConnectOption (0);
576 Config->set_input_auto_connect (bus_profile->input_ac);
577 Config->set_output_auto_connect (bus_profile->output_ac);
580 if (Config->get_use_monitor_bus() && bus_profile) {
581 add_monitor_section ();
588 Session::maybe_write_autosave()
590 if (dirty() && record_status() != Recording) {
591 save_state("", true);
596 Session::remove_pending_capture_state ()
598 std::string pending_state_file_path(_session_dir->root_path());
600 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
602 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
604 if (g_remove (pending_state_file_path.c_str()) != 0) {
605 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
606 pending_state_file_path, g_strerror (errno)) << endmsg;
610 /** Rename a state file.
611 * @param old_name Old snapshot name.
612 * @param new_name New snapshot name.
615 Session::rename_state (string old_name, string new_name)
617 if (old_name == _current_snapshot_name || old_name == _name) {
618 /* refuse to rename the current snapshot or the "main" one */
622 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
623 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
625 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
626 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
628 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
629 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
630 old_name, new_name, g_strerror(errno)) << endmsg;
634 /** Remove a state file.
635 * @param snapshot_name Snapshot name.
638 Session::remove_state (string snapshot_name)
640 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
641 // refuse to remove the current snapshot or the "main" one
645 std::string xml_path(_session_dir->root_path());
647 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
649 if (!create_backup_file (xml_path)) {
650 // don't remove it if a backup can't be made
651 // create_backup_file will log the error.
656 if (g_remove (xml_path.c_str()) != 0) {
657 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
658 xml_path, g_strerror (errno)) << endmsg;
662 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
664 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
667 std::string xml_path(_session_dir->root_path());
669 if (!_writable || (_state_of_the_state & CannotSave)) {
673 if (!_engine.connected ()) {
674 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
680 /* tell sources we're saving first, in case they write out to a new file
681 * which should be saved with the state rather than the old one */
682 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
684 i->second->session_saved();
685 } catch (Evoral::SMF::FileError& e) {
686 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
690 SaveSession (); /* EMIT SIGNAL */
692 tree.set_root (&get_state());
694 if (snapshot_name.empty()) {
695 snapshot_name = _current_snapshot_name;
696 } else if (switch_to_snapshot) {
697 _current_snapshot_name = snapshot_name;
702 /* proper save: use statefile_suffix (.ardour in English) */
704 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
706 /* make a backup copy of the old file */
708 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
709 // create_backup_file will log the error
715 /* pending save: use pending_suffix (.pending in English) */
716 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
719 std::string tmp_path(_session_dir->root_path());
720 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
722 // cerr << "actually writing state to " << xml_path << endl;
724 if (!tree.write (tmp_path)) {
725 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
726 if (g_remove (tmp_path.c_str()) != 0) {
727 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
728 tmp_path, g_strerror (errno)) << endmsg;
734 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
735 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
736 tmp_path, xml_path, g_strerror(errno)) << endmsg;
737 if (g_remove (tmp_path.c_str()) != 0) {
738 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
739 tmp_path, g_strerror (errno)) << endmsg;
747 save_history (snapshot_name);
749 bool was_dirty = dirty();
751 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
754 DirtyChanged (); /* EMIT SIGNAL */
757 StateSaved (snapshot_name); /* EMIT SIGNAL */
764 Session::restore_state (string snapshot_name)
766 if (load_state (snapshot_name) == 0) {
767 set_state (*state_tree->root(), Stateful::loading_state_version);
774 Session::load_state (string snapshot_name)
779 state_was_pending = false;
781 /* check for leftover pending state from a crashed capture attempt */
783 std::string xmlpath(_session_dir->root_path());
784 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
786 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
788 /* there is pending state from a crashed capture attempt */
790 boost::optional<int> r = AskAboutPendingState();
791 if (r.get_value_or (1)) {
792 state_was_pending = true;
796 if (!state_was_pending) {
797 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
800 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
801 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
802 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
803 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
808 state_tree = new XMLTree;
812 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
814 if (!state_tree->read (xmlpath)) {
815 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
821 XMLNode& root (*state_tree->root());
823 if (root.name() != X_("Session")) {
824 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
830 const XMLProperty* prop;
832 if ((prop = root.property ("version")) == 0) {
833 /* no version implies very old version of Ardour */
834 Stateful::loading_state_version = 1000;
836 if (prop->value().find ('.') != string::npos) {
837 /* old school version format */
838 if (prop->value()[0] == '2') {
839 Stateful::loading_state_version = 2000;
841 Stateful::loading_state_version = 3000;
844 Stateful::loading_state_version = atoi (prop->value());
848 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
850 std::string backup_path(_session_dir->root_path());
851 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
852 backup_path = Glib::build_filename (backup_path, backup_filename);
854 // only create a backup for a given statefile version once
856 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
858 VersionMismatch (xmlpath, backup_path);
860 if (!copy_file (xmlpath, backup_path)) {;
870 Session::load_options (const XMLNode& node)
872 LocaleGuard lg (X_("POSIX"));
873 config.set_variables (node);
884 Session::get_template()
886 /* if we don't disable rec-enable, diskstreams
887 will believe they need to store their capture
888 sources in their state node.
891 disable_record (false);
897 Session::state (bool full_state)
899 XMLNode* node = new XMLNode("Session");
903 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
904 node->add_property("version", buf);
906 /* store configuration settings */
910 node->add_property ("name", _name);
911 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
912 node->add_property ("sample-rate", buf);
914 if (session_dirs.size() > 1) {
918 vector<space_and_path>::iterator i = session_dirs.begin();
919 vector<space_and_path>::iterator next;
921 ++i; /* skip the first one */
925 while (i != session_dirs.end()) {
929 if (next != session_dirs.end()) {
930 p += G_SEARCHPATH_SEPARATOR;
939 child = node->add_child ("Path");
940 child->add_content (p);
944 /* save the ID counter */
946 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
947 node->add_property ("id-counter", buf);
949 /* save the event ID counter */
951 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
952 node->add_property ("event-counter", buf);
954 /* various options */
956 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
957 if (!midi_port_nodes.empty()) {
958 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
959 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
960 midi_port_stuff->add_child_nocopy (**n);
962 node->add_child_nocopy (*midi_port_stuff);
965 node->add_child_nocopy (config.get_variables ());
967 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
969 child = node->add_child ("Sources");
972 Glib::Threads::Mutex::Lock sl (source_lock);
974 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
976 /* Don't save information about non-file Sources, or
977 * about non-destructive file sources that are empty
978 * and unused by any regions.
981 boost::shared_ptr<FileSource> fs;
983 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
985 if (!fs->destructive()) {
986 if (fs->empty() && !fs->used()) {
991 child->add_child_nocopy (siter->second->get_state());
996 child = node->add_child ("Regions");
999 Glib::Threads::Mutex::Lock rl (region_lock);
1000 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1001 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1002 boost::shared_ptr<Region> r = i->second;
1003 /* only store regions not attached to playlists */
1004 if (r->playlist() == 0) {
1005 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1006 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1008 child->add_child_nocopy (r->get_state ());
1013 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1015 if (!cassocs.empty()) {
1016 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1018 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1020 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1021 i->first->id().print (buf, sizeof (buf));
1022 can->add_property (X_("copy"), buf);
1023 i->second->id().print (buf, sizeof (buf));
1024 can->add_property (X_("original"), buf);
1025 ca->add_child_nocopy (*can);
1031 node->add_child_nocopy (_locations->get_state());
1033 // for a template, just create a new Locations, populate it
1034 // with the default start and end, and get the state for that.
1035 Locations loc (*this);
1036 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1037 range->set (max_framepos, 0);
1039 node->add_child_nocopy (loc.get_state());
1042 child = node->add_child ("Bundles");
1044 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1045 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1046 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1048 child->add_child_nocopy (b->get_state());
1053 child = node->add_child ("Routes");
1055 boost::shared_ptr<RouteList> r = routes.reader ();
1057 RoutePublicOrderSorter cmp;
1058 RouteList public_order (*r);
1059 public_order.sort (cmp);
1061 /* the sort should have put control outs first */
1064 assert (_monitor_out == public_order.front());
1067 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1068 if (!(*i)->is_auditioner()) {
1070 child->add_child_nocopy ((*i)->get_state());
1072 child->add_child_nocopy ((*i)->get_template());
1078 playlists->add_state (node, full_state);
1080 child = node->add_child ("RouteGroups");
1081 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1082 child->add_child_nocopy ((*i)->get_state());
1086 XMLNode* gain_child = node->add_child ("Click");
1087 gain_child->add_child_nocopy (_click_io->state (full_state));
1088 gain_child->add_child_nocopy (_click_gain->state (full_state));
1092 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1093 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1097 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1098 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1101 node->add_child_nocopy (_speakers->get_state());
1102 node->add_child_nocopy (_tempo_map->get_state());
1103 node->add_child_nocopy (get_control_protocol_state());
1106 node->add_child_copy (*_extra_xml);
1113 Session::get_control_protocol_state ()
1115 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1116 return cpm.get_state();
1120 Session::set_state (const XMLNode& node, int version)
1124 const XMLProperty* prop;
1127 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1129 if (node.name() != X_("Session")) {
1130 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1134 if ((prop = node.property ("name")) != 0) {
1135 _name = prop->value ();
1138 if ((prop = node.property (X_("sample-rate"))) != 0) {
1140 _nominal_frame_rate = atoi (prop->value());
1142 if (_nominal_frame_rate != _current_frame_rate) {
1143 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1144 if (r.get_value_or (0)) {
1150 setup_raid_path(_session_dir->root_path());
1152 if ((prop = node.property (X_("id-counter"))) != 0) {
1154 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1155 ID::init_counter (x);
1157 /* old sessions used a timebased counter, so fake
1158 the startup ID counter based on a standard
1163 ID::init_counter (now);
1166 if ((prop = node.property (X_("event-counter"))) != 0) {
1167 Evoral::init_event_id_counter (atoi (prop->value()));
1171 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1172 _midi_ports->set_midi_port_states (child->children());
1175 IO::disable_connecting ();
1177 Stateful::save_extra_xml (node);
1179 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1180 load_options (*child);
1181 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1182 load_options (*child);
1184 error << _("Session: XML state has no options section") << endmsg;
1187 if (version >= 3000) {
1188 if ((child = find_named_node (node, "Metadata")) == 0) {
1189 warning << _("Session: XML state has no metadata section") << endmsg;
1190 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1195 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1196 _speakers->set_state (*child, version);
1199 if ((child = find_named_node (node, "Sources")) == 0) {
1200 error << _("Session: XML state has no sources section") << endmsg;
1202 } else if (load_sources (*child)) {
1206 if ((child = find_named_node (node, "TempoMap")) == 0) {
1207 error << _("Session: XML state has no Tempo Map section") << endmsg;
1209 } else if (_tempo_map->set_state (*child, version)) {
1213 if ((child = find_named_node (node, "Locations")) == 0) {
1214 error << _("Session: XML state has no locations section") << endmsg;
1216 } else if (_locations->set_state (*child, version)) {
1222 if ((location = _locations->auto_loop_location()) != 0) {
1223 set_auto_loop_location (location);
1226 if ((location = _locations->auto_punch_location()) != 0) {
1227 set_auto_punch_location (location);
1230 if ((location = _locations->session_range_location()) != 0) {
1231 delete _session_range_location;
1232 _session_range_location = location;
1235 if (_session_range_location) {
1236 AudioFileSource::set_header_position_offset (_session_range_location->start());
1239 if ((child = find_named_node (node, "Regions")) == 0) {
1240 error << _("Session: XML state has no Regions section") << endmsg;
1242 } else if (load_regions (*child)) {
1246 if ((child = find_named_node (node, "Playlists")) == 0) {
1247 error << _("Session: XML state has no playlists section") << endmsg;
1249 } else if (playlists->load (*this, *child)) {
1253 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1255 } else if (playlists->load_unused (*this, *child)) {
1259 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1260 if (load_compounds (*child)) {
1265 if (version >= 3000) {
1266 if ((child = find_named_node (node, "Bundles")) == 0) {
1267 warning << _("Session: XML state has no bundles section") << endmsg;
1270 /* We can't load Bundles yet as they need to be able
1271 to convert from port names to Port objects, which can't happen until
1273 _bundle_xml_node = new XMLNode (*child);
1277 if (version < 3000) {
1278 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1279 error << _("Session: XML state has no diskstreams section") << endmsg;
1281 } else if (load_diskstreams_2X (*child, version)) {
1286 if ((child = find_named_node (node, "Routes")) == 0) {
1287 error << _("Session: XML state has no routes section") << endmsg;
1289 } else if (load_routes (*child, version)) {
1293 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1294 _diskstreams_2X.clear ();
1296 if (version >= 3000) {
1298 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1299 error << _("Session: XML state has no route groups section") << endmsg;
1301 } else if (load_route_groups (*child, version)) {
1305 } else if (version < 3000) {
1307 if ((child = find_named_node (node, "EditGroups")) == 0) {
1308 error << _("Session: XML state has no edit groups section") << endmsg;
1310 } else if (load_route_groups (*child, version)) {
1314 if ((child = find_named_node (node, "MixGroups")) == 0) {
1315 error << _("Session: XML state has no mix groups section") << endmsg;
1317 } else if (load_route_groups (*child, version)) {
1322 if ((child = find_named_node (node, "Click")) == 0) {
1323 warning << _("Session: XML state has no click section") << endmsg;
1324 } else if (_click_io) {
1325 setup_click_state (&node);
1328 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1329 ControlProtocolManager::instance().set_state (*child, version);
1332 update_have_rec_enabled_track ();
1334 /* here beginneth the second phase ... */
1336 StateReady (); /* EMIT SIGNAL */
1345 Session::load_routes (const XMLNode& node, int version)
1348 XMLNodeConstIterator niter;
1349 RouteList new_routes;
1351 nlist = node.children();
1355 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1357 boost::shared_ptr<Route> route;
1358 if (version < 3000) {
1359 route = XMLRouteFactory_2X (**niter, version);
1361 route = XMLRouteFactory (**niter, version);
1365 error << _("Session: cannot create Route from XML description.") << endmsg;
1369 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1371 new_routes.push_back (route);
1374 add_routes (new_routes, false, false, false);
1379 boost::shared_ptr<Route>
1380 Session::XMLRouteFactory (const XMLNode& node, int version)
1382 boost::shared_ptr<Route> ret;
1384 if (node.name() != "Route") {
1388 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1390 DataType type = DataType::AUDIO;
1391 const XMLProperty* prop = node.property("default-type");
1394 type = DataType (prop->value());
1397 assert (type != DataType::NIL);
1401 boost::shared_ptr<Track> track;
1403 if (type == DataType::AUDIO) {
1404 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1406 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1409 if (track->init()) {
1413 if (track->set_state (node, version)) {
1417 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1418 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1423 enum Route::Flag flags = Route::Flag(0);
1424 const XMLProperty* prop = node.property("flags");
1426 flags = Route::Flag (string_2_enum (prop->value(), flags));
1429 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1431 if (r->init () == 0 && r->set_state (node, version) == 0) {
1432 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1433 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1442 boost::shared_ptr<Route>
1443 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1445 boost::shared_ptr<Route> ret;
1447 if (node.name() != "Route") {
1451 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1453 ds_prop = node.property (X_("diskstream"));
1456 DataType type = DataType::AUDIO;
1457 const XMLProperty* prop = node.property("default-type");
1460 type = DataType (prop->value());
1463 assert (type != DataType::NIL);
1467 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1468 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1472 if (i == _diskstreams_2X.end()) {
1473 error << _("Could not find diskstream for route") << endmsg;
1474 return boost::shared_ptr<Route> ();
1477 boost::shared_ptr<Track> track;
1479 if (type == DataType::AUDIO) {
1480 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1482 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1485 if (track->init()) {
1489 if (track->set_state (node, version)) {
1493 track->set_diskstream (*i);
1495 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1496 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1501 enum Route::Flag flags = Route::Flag(0);
1502 const XMLProperty* prop = node.property("flags");
1504 flags = Route::Flag (string_2_enum (prop->value(), flags));
1507 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1509 if (r->init () == 0 && r->set_state (node, version) == 0) {
1510 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1511 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1521 Session::load_regions (const XMLNode& node)
1524 XMLNodeConstIterator niter;
1525 boost::shared_ptr<Region> region;
1527 nlist = node.children();
1531 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1532 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1533 error << _("Session: cannot create Region from XML description.");
1534 const XMLProperty *name = (**niter).property("name");
1537 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1548 Session::load_compounds (const XMLNode& node)
1550 XMLNodeList calist = node.children();
1551 XMLNodeConstIterator caiter;
1552 XMLProperty *caprop;
1554 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1555 XMLNode* ca = *caiter;
1559 if ((caprop = ca->property (X_("original"))) == 0) {
1562 orig_id = caprop->value();
1564 if ((caprop = ca->property (X_("copy"))) == 0) {
1567 copy_id = caprop->value();
1569 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1570 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1572 if (!orig || !copy) {
1573 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1579 RegionFactory::add_compound_association (orig, copy);
1586 Session::load_nested_sources (const XMLNode& node)
1589 XMLNodeConstIterator niter;
1591 nlist = node.children();
1593 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1594 if ((*niter)->name() == "Source") {
1596 /* it may already exist, so don't recreate it unnecessarily
1599 XMLProperty* prop = (*niter)->property (X_("id"));
1601 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1605 ID source_id (prop->value());
1607 if (!source_by_id (source_id)) {
1610 SourceFactory::create (*this, **niter, true);
1612 catch (failed_constructor& err) {
1613 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1620 boost::shared_ptr<Region>
1621 Session::XMLRegionFactory (const XMLNode& node, bool full)
1623 const XMLProperty* type = node.property("type");
1627 const XMLNodeList& nlist = node.children();
1629 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1630 XMLNode *child = (*niter);
1631 if (child->name() == "NestedSource") {
1632 load_nested_sources (*child);
1636 if (!type || type->value() == "audio") {
1637 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1638 } else if (type->value() == "midi") {
1639 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1642 } catch (failed_constructor& err) {
1643 return boost::shared_ptr<Region> ();
1646 return boost::shared_ptr<Region> ();
1649 boost::shared_ptr<AudioRegion>
1650 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1652 const XMLProperty* prop;
1653 boost::shared_ptr<Source> source;
1654 boost::shared_ptr<AudioSource> as;
1656 SourceList master_sources;
1657 uint32_t nchans = 1;
1660 if (node.name() != X_("Region")) {
1661 return boost::shared_ptr<AudioRegion>();
1664 if ((prop = node.property (X_("channels"))) != 0) {
1665 nchans = atoi (prop->value().c_str());
1668 if ((prop = node.property ("name")) == 0) {
1669 cerr << "no name for this region\n";
1673 if ((prop = node.property (X_("source-0"))) == 0) {
1674 if ((prop = node.property ("source")) == 0) {
1675 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1676 return boost::shared_ptr<AudioRegion>();
1680 PBD::ID s_id (prop->value());
1682 if ((source = source_by_id (s_id)) == 0) {
1683 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1684 return boost::shared_ptr<AudioRegion>();
1687 as = boost::dynamic_pointer_cast<AudioSource>(source);
1689 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1690 return boost::shared_ptr<AudioRegion>();
1693 sources.push_back (as);
1695 /* pickup other channels */
1697 for (uint32_t n=1; n < nchans; ++n) {
1698 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1699 if ((prop = node.property (buf)) != 0) {
1701 PBD::ID id2 (prop->value());
1703 if ((source = source_by_id (id2)) == 0) {
1704 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1705 return boost::shared_ptr<AudioRegion>();
1708 as = boost::dynamic_pointer_cast<AudioSource>(source);
1710 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1711 return boost::shared_ptr<AudioRegion>();
1713 sources.push_back (as);
1717 for (uint32_t n = 0; n < nchans; ++n) {
1718 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1719 if ((prop = node.property (buf)) != 0) {
1721 PBD::ID id2 (prop->value());
1723 if ((source = source_by_id (id2)) == 0) {
1724 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1725 return boost::shared_ptr<AudioRegion>();
1728 as = boost::dynamic_pointer_cast<AudioSource>(source);
1730 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1731 return boost::shared_ptr<AudioRegion>();
1733 master_sources.push_back (as);
1738 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1740 /* a final detail: this is the one and only place that we know how long missing files are */
1742 if (region->whole_file()) {
1743 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1744 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1746 sfp->set_length (region->length());
1751 if (!master_sources.empty()) {
1752 if (master_sources.size() != nchans) {
1753 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1755 region->set_master_sources (master_sources);
1763 catch (failed_constructor& err) {
1764 return boost::shared_ptr<AudioRegion>();
1768 boost::shared_ptr<MidiRegion>
1769 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1771 const XMLProperty* prop;
1772 boost::shared_ptr<Source> source;
1773 boost::shared_ptr<MidiSource> ms;
1776 if (node.name() != X_("Region")) {
1777 return boost::shared_ptr<MidiRegion>();
1780 if ((prop = node.property ("name")) == 0) {
1781 cerr << "no name for this region\n";
1785 if ((prop = node.property (X_("source-0"))) == 0) {
1786 if ((prop = node.property ("source")) == 0) {
1787 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1788 return boost::shared_ptr<MidiRegion>();
1792 PBD::ID s_id (prop->value());
1794 if ((source = source_by_id (s_id)) == 0) {
1795 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1796 return boost::shared_ptr<MidiRegion>();
1799 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1801 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1802 return boost::shared_ptr<MidiRegion>();
1805 sources.push_back (ms);
1808 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1809 /* a final detail: this is the one and only place that we know how long missing files are */
1811 if (region->whole_file()) {
1812 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1813 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1815 sfp->set_length (region->length());
1823 catch (failed_constructor& err) {
1824 return boost::shared_ptr<MidiRegion>();
1829 Session::get_sources_as_xml ()
1832 XMLNode* node = new XMLNode (X_("Sources"));
1833 Glib::Threads::Mutex::Lock lm (source_lock);
1835 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1836 node->add_child_nocopy (i->second->get_state());
1843 Session::path_from_region_name (DataType type, string name, string identifier)
1845 char buf[PATH_MAX+1];
1847 SessionDirectory sdir(get_best_session_directory_for_new_source());
1848 std::string source_dir = ((type == DataType::AUDIO)
1849 ? sdir.sound_path() : sdir.midi_path());
1851 string ext = native_header_format_extension (config.get_native_file_header_format(), type);
1853 for (n = 0; n < 999999; ++n) {
1854 if (identifier.length()) {
1855 snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
1856 identifier.c_str(), n, ext.c_str());
1858 snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
1862 std::string source_path = Glib::build_filename (source_dir, buf);
1864 if (!Glib::file_test (source_path, Glib::FILE_TEST_EXISTS)) {
1869 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1878 Session::load_sources (const XMLNode& node)
1881 XMLNodeConstIterator niter;
1882 boost::shared_ptr<Source> source;
1884 nlist = node.children();
1888 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1891 if ((source = XMLSourceFactory (**niter)) == 0) {
1892 error << _("Session: cannot create Source from XML description.") << endmsg;
1895 } catch (MissingSource& err) {
1899 if (!no_questions_about_missing_files) {
1900 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1905 switch (user_choice) {
1907 /* user added a new search location, so try again */
1912 /* user asked to quit the entire session load
1917 no_questions_about_missing_files = true;
1921 no_questions_about_missing_files = true;
1926 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1927 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1936 boost::shared_ptr<Source>
1937 Session::XMLSourceFactory (const XMLNode& node)
1939 if (node.name() != "Source") {
1940 return boost::shared_ptr<Source>();
1944 /* note: do peak building in another thread when loading session state */
1945 return SourceFactory::create (*this, node, true);
1948 catch (failed_constructor& err) {
1949 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
1950 return boost::shared_ptr<Source>();
1955 Session::save_template (string template_name)
1959 if (_state_of_the_state & CannotSave) {
1963 std::string user_template_dir(user_template_directory());
1965 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
1966 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
1967 user_template_dir, g_strerror (errno)) << endmsg;
1971 tree.set_root (&get_template());
1973 std::string template_dir_path(user_template_dir);
1975 /* directory to put the template in */
1976 template_dir_path = Glib::build_filename (template_dir_path, template_name);
1978 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
1979 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
1980 template_dir_path) << endmsg;
1984 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
1985 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
1986 template_dir_path, g_strerror (errno)) << endmsg;
1991 std::string template_file_path(template_dir_path);
1992 template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
1994 if (!tree.write (template_file_path)) {
1995 error << _("template not saved") << endmsg;
1999 /* copy plugin state directory */
2001 std::string template_plugin_state_path(template_dir_path);
2002 template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
2004 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2005 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2006 template_plugin_state_path, g_strerror (errno)) << endmsg;
2010 copy_files (plugins_dir(), template_plugin_state_path);
2016 Session::refresh_disk_space ()
2018 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2020 Glib::Threads::Mutex::Lock lm (space_lock);
2022 /* get freespace on every FS that is part of the session path */
2024 _total_free_4k_blocks = 0;
2025 _total_free_4k_blocks_uncertain = false;
2027 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2029 struct statfs statfsbuf;
2030 statfs (i->path.c_str(), &statfsbuf);
2032 double const scale = statfsbuf.f_bsize / 4096.0;
2034 /* See if this filesystem is read-only */
2035 struct statvfs statvfsbuf;
2036 statvfs (i->path.c_str(), &statvfsbuf);
2038 /* f_bavail can be 0 if it is undefined for whatever
2039 filesystem we are looking at; Samba shares mounted
2040 via GVFS are an example of this.
2042 if (statfsbuf.f_bavail == 0) {
2043 /* block count unknown */
2045 i->blocks_unknown = true;
2046 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2047 /* read-only filesystem */
2049 i->blocks_unknown = false;
2051 /* read/write filesystem with known space */
2052 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2053 i->blocks_unknown = false;
2056 _total_free_4k_blocks += i->blocks;
2057 if (i->blocks_unknown) {
2058 _total_free_4k_blocks_uncertain = true;
2061 #elif defined (COMPILER_MSVC)
2062 vector<string> scanned_volumes;
2063 vector<string>::iterator j;
2064 vector<space_and_path>::iterator i;
2065 DWORD nSectorsPerCluster, nBytesPerSector,
2066 nFreeClusters, nTotalClusters;
2070 _total_free_4k_blocks = 0;
2072 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2073 strncpy (disk_drive, (*i).path.c_str(), 3);
2077 volume_found = false;
2078 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2080 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2081 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2082 i->blocks = (uint32_t)(nFreeBytes / 4096);
2084 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2085 if (0 == j->compare(disk_drive)) {
2086 volume_found = true;
2091 if (!volume_found) {
2092 scanned_volumes.push_back(disk_drive);
2093 _total_free_4k_blocks += i->blocks;
2098 if (0 == _total_free_4k_blocks) {
2099 strncpy (disk_drive, path().c_str(), 3);
2102 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2104 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2105 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2106 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2113 Session::get_best_session_directory_for_new_source ()
2115 vector<space_and_path>::iterator i;
2116 string result = _session_dir->root_path();
2118 /* handle common case without system calls */
2120 if (session_dirs.size() == 1) {
2124 /* OK, here's the algorithm we're following here:
2126 We want to select which directory to use for
2127 the next file source to be created. Ideally,
2128 we'd like to use a round-robin process so as to
2129 get maximum performance benefits from splitting
2130 the files across multiple disks.
2132 However, in situations without much diskspace, an
2133 RR approach may end up filling up a filesystem
2134 with new files while others still have space.
2135 Its therefore important to pay some attention to
2136 the freespace in the filesystem holding each
2137 directory as well. However, if we did that by
2138 itself, we'd keep creating new files in the file
2139 system with the most space until it was as full
2140 as all others, thus negating any performance
2141 benefits of this RAID-1 like approach.
2143 So, we use a user-configurable space threshold. If
2144 there are at least 2 filesystems with more than this
2145 much space available, we use RR selection between them.
2146 If not, then we pick the filesystem with the most space.
2148 This gets a good balance between the two
2152 refresh_disk_space ();
2154 int free_enough = 0;
2156 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2157 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2162 if (free_enough >= 2) {
2163 /* use RR selection process, ensuring that the one
2167 i = last_rr_session_dir;
2170 if (++i == session_dirs.end()) {
2171 i = session_dirs.begin();
2174 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2175 SessionDirectory sdir(i->path);
2176 if (sdir.create ()) {
2178 last_rr_session_dir = i;
2183 } while (i != last_rr_session_dir);
2187 /* pick FS with the most freespace (and that
2188 seems to actually work ...)
2191 vector<space_and_path> sorted;
2192 space_and_path_ascending_cmp cmp;
2194 sorted = session_dirs;
2195 sort (sorted.begin(), sorted.end(), cmp);
2197 for (i = sorted.begin(); i != sorted.end(); ++i) {
2198 SessionDirectory sdir(i->path);
2199 if (sdir.create ()) {
2201 last_rr_session_dir = i;
2211 Session::automation_dir () const
2213 return Glib::build_filename (_path, "automation");
2217 Session::analysis_dir () const
2219 return Glib::build_filename (_path, "analysis");
2223 Session::plugins_dir () const
2225 return Glib::build_filename (_path, "plugins");
2229 Session::externals_dir () const
2231 return Glib::build_filename (_path, "externals");
2235 Session::load_bundles (XMLNode const & node)
2237 XMLNodeList nlist = node.children();
2238 XMLNodeConstIterator niter;
2242 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2243 if ((*niter)->name() == "InputBundle") {
2244 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2245 } else if ((*niter)->name() == "OutputBundle") {
2246 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2248 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2257 Session::load_route_groups (const XMLNode& node, int version)
2259 XMLNodeList nlist = node.children();
2260 XMLNodeConstIterator niter;
2264 if (version >= 3000) {
2266 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2267 if ((*niter)->name() == "RouteGroup") {
2268 RouteGroup* rg = new RouteGroup (*this, "");
2269 add_route_group (rg);
2270 rg->set_state (**niter, version);
2274 } else if (version < 3000) {
2276 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2277 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2278 RouteGroup* rg = new RouteGroup (*this, "");
2279 add_route_group (rg);
2280 rg->set_state (**niter, version);
2289 Session::auto_save()
2291 save_state (_current_snapshot_name);
2295 state_file_filter (const string &str, void* /*arg*/)
2297 return (str.length() > strlen(statefile_suffix) &&
2298 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2302 remove_end(string state)
2304 string statename(state);
2306 string::size_type start,end;
2307 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2308 statename = statename.substr (start+1);
2311 if ((end = statename.rfind(".ardour")) == string::npos) {
2312 end = statename.length();
2315 return string(statename.substr (0, end));
2319 Session::possible_states (string path)
2321 vector<string> states;
2322 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2324 transform(states.begin(), states.end(), states.begin(), remove_end);
2326 sort (states.begin(), states.end());
2332 Session::possible_states () const
2334 return possible_states(_path);
2338 Session::add_route_group (RouteGroup* g)
2340 _route_groups.push_back (g);
2341 route_group_added (g); /* EMIT SIGNAL */
2343 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2344 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2345 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2351 Session::remove_route_group (RouteGroup& rg)
2353 list<RouteGroup*>::iterator i;
2355 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2356 _route_groups.erase (i);
2359 route_group_removed (); /* EMIT SIGNAL */
2363 /** Set a new order for our route groups, without adding or removing any.
2364 * @param groups Route group list in the new order.
2367 Session::reorder_route_groups (list<RouteGroup*> groups)
2369 _route_groups = groups;
2371 route_groups_reordered (); /* EMIT SIGNAL */
2377 Session::route_group_by_name (string name)
2379 list<RouteGroup *>::iterator i;
2381 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2382 if ((*i)->name() == name) {
2390 Session::all_route_group() const
2392 return *_all_route_group;
2396 Session::add_commands (vector<Command*> const & cmds)
2398 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2404 Session::begin_reversible_command (const string& name)
2406 begin_reversible_command (g_quark_from_string (name.c_str ()));
2409 /** Begin a reversible command using a GQuark to identify it.
2410 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2411 * but there must be as many begin...()s as there are commit...()s.
2414 Session::begin_reversible_command (GQuark q)
2416 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2417 to hold all the commands that are committed. This keeps the order of
2418 commands correct in the history.
2421 if (_current_trans == 0) {
2422 /* start a new transaction */
2423 assert (_current_trans_quarks.empty ());
2424 _current_trans = new UndoTransaction();
2425 _current_trans->set_name (g_quark_to_string (q));
2428 _current_trans_quarks.push_front (q);
2432 Session::commit_reversible_command (Command *cmd)
2434 assert (_current_trans);
2435 assert (!_current_trans_quarks.empty ());
2440 _current_trans->add_command (cmd);
2443 _current_trans_quarks.pop_front ();
2445 if (!_current_trans_quarks.empty ()) {
2446 /* the transaction we're committing is not the top-level one */
2450 if (_current_trans->empty()) {
2451 /* no commands were added to the transaction, so just get rid of it */
2452 delete _current_trans;
2457 gettimeofday (&now, 0);
2458 _current_trans->set_timestamp (now);
2460 _history.add (_current_trans);
2465 accept_all_audio_files (const string& path, void* /*arg*/)
2467 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2471 if (!AudioFileSource::safe_audio_file_extension (path)) {
2479 accept_all_midi_files (const string& path, void* /*arg*/)
2481 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2485 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2486 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2487 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2491 accept_all_state_files (const string& path, void* /*arg*/)
2493 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2497 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2501 Session::find_all_sources (string path, set<string>& result)
2506 if (!tree.read (path)) {
2510 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2515 XMLNodeConstIterator niter;
2517 nlist = node->children();
2521 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2525 if ((prop = (*niter)->property (X_("type"))) == 0) {
2529 DataType type (prop->value());
2531 if ((prop = (*niter)->property (X_("name"))) == 0) {
2535 if (Glib::path_is_absolute (prop->value())) {
2536 /* external file, ignore */
2544 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2545 result.insert (found_path);
2553 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2555 vector<string> state_files;
2557 string this_snapshot_path;
2563 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2564 ripped = ripped.substr (0, ripped.length() - 1);
2567 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2569 if (state_files.empty()) {
2574 this_snapshot_path = _path;
2575 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2576 this_snapshot_path += statefile_suffix;
2578 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2580 if (exclude_this_snapshot && *i == this_snapshot_path) {
2584 if (find_all_sources (*i, result) < 0) {
2592 struct RegionCounter {
2593 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2594 AudioSourceList::iterator iter;
2595 boost::shared_ptr<Region> region;
2598 RegionCounter() : count (0) {}
2602 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2604 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2605 return r.get_value_or (1);
2609 Session::cleanup_regions ()
2611 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2613 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2615 uint32_t used = playlists->region_use_count (i->second);
2617 if (used == 0 && !i->second->automatic ()) {
2618 RegionFactory::map_remove (i->second);
2622 /* dump the history list */
2629 Session::cleanup_sources (CleanupReport& rep)
2631 // FIXME: needs adaptation to midi
2633 vector<boost::shared_ptr<Source> > dead_sources;
2636 vector<space_and_path>::iterator i;
2637 vector<space_and_path>::iterator nexti;
2638 vector<string> candidates;
2639 vector<string> unused;
2640 set<string> all_sources;
2647 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2649 /* consider deleting all unused playlists */
2651 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2656 /* sync the "all regions" property of each playlist with its current state
2659 playlists->sync_all_regions_with_regions ();
2661 /* find all un-used sources */
2666 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2668 SourceMap::iterator tmp;
2673 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2677 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2678 dead_sources.push_back (i->second);
2679 i->second->drop_references ();
2685 /* build a list of all the possible audio directories for the session */
2687 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2692 SessionDirectory sdir ((*i).path);
2693 audio_path += sdir.sound_path();
2695 if (nexti != session_dirs.end()) {
2696 audio_path += G_SEARCHPATH_SEPARATOR;
2703 /* build a list of all the possible midi directories for the session */
2705 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2710 SessionDirectory sdir ((*i).path);
2711 midi_path += sdir.midi_path();
2713 if (nexti != session_dirs.end()) {
2714 midi_path += G_SEARCHPATH_SEPARATOR;
2720 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2721 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2723 /* find all sources, but don't use this snapshot because the
2724 state file on disk still references sources we may have already
2728 find_all_sources_across_snapshots (all_sources, true);
2730 /* add our current source list
2733 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2734 boost::shared_ptr<FileSource> fs;
2735 SourceMap::iterator tmp = i;
2738 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2740 if (!fs->is_stub()) {
2742 if (playlists->source_use_count (fs) != 0) {
2743 all_sources.insert (fs->path());
2746 /* we might not remove this source from disk, because it may be used
2747 by other snapshots, but its not being used in this version
2748 so lets get rid of it now, along with any representative regions
2752 RegionFactory::remove_regions_using_source (i->second);
2761 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2766 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2768 tmppath1 = canonical_path (spath);
2769 tmppath2 = canonical_path ((*i));
2771 if (tmppath1 == tmppath2) {
2778 unused.push_back (spath);
2782 /* now try to move all unused files into the "dead" directory(ies) */
2784 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2785 struct stat statbuf;
2789 /* don't move the file across filesystems, just
2790 stick it in the `dead_dir_name' directory
2791 on whichever filesystem it was already on.
2794 if ((*x).find ("/sounds/") != string::npos) {
2796 /* old school, go up 1 level */
2798 newpath = Glib::path_get_dirname (*x); // "sounds"
2799 newpath = Glib::path_get_dirname (newpath); // "session-name"
2803 /* new school, go up 4 levels */
2805 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2806 newpath = Glib::path_get_dirname (newpath); // "session-name"
2807 newpath = Glib::path_get_dirname (newpath); // "interchange"
2808 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2811 newpath = Glib::build_filename (newpath, dead_dir_name);
2813 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2814 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2818 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2820 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2822 /* the new path already exists, try versioning */
2824 char buf[PATH_MAX+1];
2828 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2831 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2832 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2836 if (version == 999) {
2837 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2841 newpath = newpath_v;
2846 /* it doesn't exist, or we can't read it or something */
2850 stat ((*x).c_str(), &statbuf);
2852 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2853 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2854 (*x), newpath, strerror (errno))
2859 /* see if there an easy to find peakfile for this file, and remove it.
2862 string base = basename_nosuffix (*x);
2863 base += "%A"; /* this is what we add for the channel suffix of all native files,
2864 or for the first channel of embedded files. it will miss
2865 some peakfiles for other channels
2867 string peakpath = peak_path (base);
2869 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2870 if (::g_unlink (peakpath.c_str()) != 0) {
2871 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2872 peakpath, _path, strerror (errno))
2874 /* try to back out */
2875 ::rename (newpath.c_str(), _path.c_str());
2880 rep.paths.push_back (*x);
2881 rep.space += statbuf.st_size;
2884 /* dump the history list */
2888 /* save state so we don't end up a session file
2889 referring to non-existent sources.
2896 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2902 Session::cleanup_trash_sources (CleanupReport& rep)
2904 // FIXME: needs adaptation for MIDI
2906 vector<space_and_path>::iterator i;
2912 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2914 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2916 clear_directory (dead_dir, &rep.space, &rep.paths);
2923 Session::set_dirty ()
2925 bool was_dirty = dirty();
2927 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2931 DirtyChanged(); /* EMIT SIGNAL */
2937 Session::set_clean ()
2939 bool was_dirty = dirty();
2941 _state_of_the_state = Clean;
2945 DirtyChanged(); /* EMIT SIGNAL */
2950 Session::set_deletion_in_progress ()
2952 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2956 Session::clear_deletion_in_progress ()
2958 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2962 Session::add_controllable (boost::shared_ptr<Controllable> c)
2964 /* this adds a controllable to the list managed by the Session.
2965 this is a subset of those managed by the Controllable class
2966 itself, and represents the only ones whose state will be saved
2967 as part of the session.
2970 Glib::Threads::Mutex::Lock lm (controllables_lock);
2971 controllables.insert (c);
2974 struct null_deleter { void operator()(void const *) const {} };
2977 Session::remove_controllable (Controllable* c)
2979 if (_state_of_the_state & Deletion) {
2983 Glib::Threads::Mutex::Lock lm (controllables_lock);
2985 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
2987 if (x != controllables.end()) {
2988 controllables.erase (x);
2992 boost::shared_ptr<Controllable>
2993 Session::controllable_by_id (const PBD::ID& id)
2995 Glib::Threads::Mutex::Lock lm (controllables_lock);
2997 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
2998 if ((*i)->id() == id) {
3003 return boost::shared_ptr<Controllable>();
3006 boost::shared_ptr<Controllable>
3007 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3009 boost::shared_ptr<Controllable> c;
3010 boost::shared_ptr<Route> r;
3012 switch (desc.top_level_type()) {
3013 case ControllableDescriptor::NamedRoute:
3015 std::string str = desc.top_level_name();
3016 if (str == "master") {
3018 } else if (str == "control" || str == "listen") {
3021 r = route_by_name (desc.top_level_name());
3026 case ControllableDescriptor::RemoteControlID:
3027 r = route_by_remote_id (desc.rid());
3035 switch (desc.subtype()) {
3036 case ControllableDescriptor::Gain:
3037 c = r->gain_control ();
3040 case ControllableDescriptor::Solo:
3041 c = r->solo_control();
3044 case ControllableDescriptor::Mute:
3045 c = r->mute_control();
3048 case ControllableDescriptor::Recenable:
3050 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3053 c = t->rec_enable_control ();
3058 case ControllableDescriptor::PanDirection:
3060 c = r->pannable()->pan_azimuth_control;
3064 case ControllableDescriptor::PanWidth:
3066 c = r->pannable()->pan_width_control;
3070 case ControllableDescriptor::PanElevation:
3072 c = r->pannable()->pan_elevation_control;
3076 case ControllableDescriptor::Balance:
3077 /* XXX simple pan control */
3080 case ControllableDescriptor::PluginParameter:
3082 uint32_t plugin = desc.target (0);
3083 uint32_t parameter_index = desc.target (1);
3085 /* revert to zero based counting */
3091 if (parameter_index > 0) {
3095 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3098 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3099 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3104 case ControllableDescriptor::SendGain:
3106 uint32_t send = desc.target (0);
3108 /* revert to zero-based counting */
3114 boost::shared_ptr<Processor> p = r->nth_send (send);
3117 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3118 boost::shared_ptr<Amp> a = s->amp();
3121 c = s->amp()->gain_control();
3128 /* relax and return a null pointer */
3136 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3139 Stateful::add_instant_xml (node, _path);
3142 if (write_to_config) {
3143 Config->add_instant_xml (node);
3148 Session::instant_xml (const string& node_name)
3150 return Stateful::instant_xml (node_name, _path);
3154 Session::save_history (string snapshot_name)
3162 if (snapshot_name.empty()) {
3163 snapshot_name = _current_snapshot_name;
3166 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3167 const string backup_filename = history_filename + backup_suffix;
3168 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3169 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3171 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3172 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3173 error << _("could not backup old history file, current history not saved") << endmsg;
3178 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
3182 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3184 if (!tree.write (xml_path))
3186 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3188 if (g_remove (xml_path.c_str()) != 0) {
3189 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3190 xml_path, g_strerror (errno)) << endmsg;
3192 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3193 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3194 backup_path, g_strerror (errno)) << endmsg;
3204 Session::restore_history (string snapshot_name)
3208 if (snapshot_name.empty()) {
3209 snapshot_name = _current_snapshot_name;
3212 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3213 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3215 info << "Loading history from " << xml_path << endmsg;
3217 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3218 info << string_compose (_("%1: no history file \"%2\" for this session."),
3219 _name, xml_path) << endmsg;
3223 if (!tree.read (xml_path)) {
3224 error << string_compose (_("Could not understand session history file \"%1\""),
3225 xml_path) << endmsg;
3232 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3235 UndoTransaction* ut = new UndoTransaction ();
3238 ut->set_name(t->property("name")->value());
3239 stringstream ss(t->property("tv-sec")->value());
3241 ss.str(t->property("tv-usec")->value());
3243 ut->set_timestamp(tv);
3245 for (XMLNodeConstIterator child_it = t->children().begin();
3246 child_it != t->children().end(); child_it++)
3248 XMLNode *n = *child_it;
3251 if (n->name() == "MementoCommand" ||
3252 n->name() == "MementoUndoCommand" ||
3253 n->name() == "MementoRedoCommand") {
3255 if ((c = memento_command_factory(n))) {
3259 } else if (n->name() == "NoteDiffCommand") {
3260 PBD::ID id (n->property("midi-source")->value());
3261 boost::shared_ptr<MidiSource> midi_source =
3262 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3264 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3266 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3269 } else if (n->name() == "SysExDiffCommand") {
3271 PBD::ID id (n->property("midi-source")->value());
3272 boost::shared_ptr<MidiSource> midi_source =
3273 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3275 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3277 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3280 } else if (n->name() == "PatchChangeDiffCommand") {
3282 PBD::ID id (n->property("midi-source")->value());
3283 boost::shared_ptr<MidiSource> midi_source =
3284 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3286 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3288 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3291 } else if (n->name() == "StatefulDiffCommand") {
3292 if ((c = stateful_diff_command_factory (n))) {
3293 ut->add_command (c);
3296 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3307 Session::config_changed (std::string p, bool ours)
3313 if (p == "seamless-loop") {
3315 } else if (p == "rf-speed") {
3317 } else if (p == "auto-loop") {
3319 } else if (p == "auto-input") {
3321 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3322 /* auto-input only makes a difference if we're rolling */
3323 set_track_monitor_input_status (!config.get_auto_input());
3326 } else if (p == "punch-in") {
3330 if ((location = _locations->auto_punch_location()) != 0) {
3332 if (config.get_punch_in ()) {
3333 replace_event (SessionEvent::PunchIn, location->start());
3335 remove_event (location->start(), SessionEvent::PunchIn);
3339 } else if (p == "punch-out") {
3343 if ((location = _locations->auto_punch_location()) != 0) {
3345 if (config.get_punch_out()) {
3346 replace_event (SessionEvent::PunchOut, location->end());
3348 clear_events (SessionEvent::PunchOut);
3352 } else if (p == "edit-mode") {
3354 Glib::Threads::Mutex::Lock lm (playlists->lock);
3356 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3357 (*i)->set_edit_mode (Config->get_edit_mode ());
3360 } else if (p == "use-video-sync") {
3362 waiting_for_sync_offset = config.get_use_video_sync();
3364 } else if (p == "mmc-control") {
3366 //poke_midi_thread ();
3368 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3370 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3372 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3374 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3376 } else if (p == "midi-control") {
3378 //poke_midi_thread ();
3380 } else if (p == "raid-path") {
3382 setup_raid_path (config.get_raid_path());
3384 } else if (p == "timecode-format") {
3388 } else if (p == "video-pullup") {
3392 } else if (p == "seamless-loop") {
3394 if (play_loop && transport_rolling()) {
3395 // to reset diskstreams etc
3396 request_play_loop (true);
3399 } else if (p == "rf-speed") {
3401 cumulative_rf_motion = 0;
3404 } else if (p == "click-sound") {
3406 setup_click_sounds (1);
3408 } else if (p == "click-emphasis-sound") {
3410 setup_click_sounds (-1);
3412 } else if (p == "clicking") {
3414 if (Config->get_clicking()) {
3415 if (_click_io && click_data) { // don't require emphasis data
3422 } else if (p == "click-gain") {
3425 _click_gain->set_gain (Config->get_click_gain(), this);
3428 } else if (p == "send-mtc") {
3430 if (Config->get_send_mtc ()) {
3431 /* mark us ready to send */
3432 next_quarter_frame_to_send = 0;
3435 } else if (p == "send-mmc") {
3437 _mmc->enable_send (Config->get_send_mmc ());
3439 } else if (p == "midi-feedback") {
3441 session_midi_feedback = Config->get_midi_feedback();
3443 } else if (p == "jack-time-master") {
3445 engine().reset_timebase ();
3447 } else if (p == "native-file-header-format") {
3449 if (!first_file_header_format_reset) {
3450 reset_native_file_format ();
3453 first_file_header_format_reset = false;
3455 } else if (p == "native-file-data-format") {
3457 if (!first_file_data_format_reset) {
3458 reset_native_file_format ();
3461 first_file_data_format_reset = false;
3463 } else if (p == "external-sync") {
3464 if (!config.get_external_sync()) {
3465 drop_sync_source ();
3467 switch_to_sync_source (Config->get_sync_source());
3469 } else if (p == "denormal-model") {
3471 } else if (p == "history-depth") {
3472 set_history_depth (Config->get_history_depth());
3473 } else if (p == "remote-model") {
3474 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3477 } else if (p == "initial-program-change") {
3479 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3482 buf[0] = MIDI::program; // channel zero by default
3483 buf[1] = (Config->get_initial_program_change() & 0x7f);
3485 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3487 } else if (p == "solo-mute-override") {
3488 // catch_up_on_solo_mute_override ();
3489 } else if (p == "listen-position" || p == "pfl-position") {
3490 listen_position_changed ();
3491 } else if (p == "solo-control-is-listen-control") {
3492 solo_control_mode_changed ();
3493 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3494 last_timecode_valid = false;
3495 } else if (p == "playback-buffer-seconds") {
3496 AudioSource::allocate_working_buffers (frame_rate());
3497 } else if (p == "automation-thinning-factor") {
3498 Evoral::ControlList::set_thinning_factor (Config->get_automation_thinning_factor());
3499 } else if (p == "ltc-source-port") {
3500 reconnect_ltc_input ();
3501 } else if (p == "ltc-sink-port") {
3502 reconnect_ltc_output ();
3503 } else if (p == "timecode-generator-offset") {
3504 ltc_tx_parse_offset();
3511 Session::set_history_depth (uint32_t d)
3513 _history.set_depth (d);
3517 Session::load_diskstreams_2X (XMLNode const & node, int)
3520 XMLNodeConstIterator citer;
3522 clist = node.children();
3524 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3527 /* diskstreams added automatically by DiskstreamCreated handler */
3528 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3529 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3530 _diskstreams_2X.push_back (dsp);
3532 error << _("Session: unknown diskstream type in XML") << endmsg;
3536 catch (failed_constructor& err) {
3537 error << _("Session: could not load diskstream via XML state") << endmsg;
3545 /** Connect things to the MMC object */
3547 Session::setup_midi_machine_control ()
3549 _mmc = new MIDI::MachineControl;
3550 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3552 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3553 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3554 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3555 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3556 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3557 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3558 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3559 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3560 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3561 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3562 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3563 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3564 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3566 /* also handle MIDI SPP because its so common */
3568 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3569 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3570 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3573 boost::shared_ptr<Controllable>
3574 Session::solo_cut_control() const
3576 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3577 controls in Ardour that currently get presented to the user in the GUI that require
3578 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3580 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3581 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3585 return _solo_cut_control;
3589 Session::rename (const std::string& new_name)
3591 string legal_name = legalize_for_path (new_name);
3597 string const old_sources_root = _session_dir->sources_root();
3602 * interchange subdirectory
3606 * Backup files are left unchanged and not renamed.
3609 /* pass one: not 100% safe check that the new directory names don't
3613 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3618 /* this is a stupid hack because Glib::path_get_dirname() is
3619 * lexical-only, and so passing it /a/b/c/ gives a different
3620 * result than passing it /a/b/c ...
3623 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3624 oldstr = oldstr.substr (0, oldstr.length() - 1);
3627 string base = Glib::path_get_dirname (oldstr);
3628 string p = Glib::path_get_basename (oldstr);
3630 newstr = Glib::build_filename (base, legal_name);
3632 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3639 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3644 /* this is a stupid hack because Glib::path_get_dirname() is
3645 * lexical-only, and so passing it /a/b/c/ gives a different
3646 * result than passing it /a/b/c ...
3649 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3650 oldstr = oldstr.substr (0, oldstr.length() - 1);
3653 string base = Glib::path_get_dirname (oldstr);
3654 string p = Glib::path_get_basename (oldstr);
3656 newstr = Glib::build_filename (base, legal_name);
3658 cerr << "Rename " << oldstr << " => " << newstr << endl;
3660 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3661 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3666 (*_session_dir) = newstr;
3671 /* directory below interchange */
3673 v.push_back (newstr);
3674 v.push_back (interchange_dir_name);
3677 oldstr = Glib::build_filename (v);
3680 v.push_back (newstr);
3681 v.push_back (interchange_dir_name);
3682 v.push_back (legal_name);
3684 newstr = Glib::build_filename (v);
3686 cerr << "Rename " << oldstr << " => " << newstr << endl;
3688 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3689 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3696 oldstr = Glib::build_filename (newpath, _current_snapshot_name) + statefile_suffix;
3697 newstr= Glib::build_filename (newpath, legal_name) + statefile_suffix;
3699 cerr << "Rename " << oldstr << " => " << newstr << endl;
3701 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3702 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3709 oldstr = Glib::build_filename (newpath, _current_snapshot_name) + history_suffix;
3711 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3712 newstr = Glib::build_filename (newpath, legal_name) + history_suffix;
3714 cerr << "Rename " << oldstr << " => " << newstr << endl;
3716 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3717 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3722 /* update file source paths */
3724 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3725 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3727 string p = fs->path ();
3728 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3733 /* remove old name from recent sessions */
3735 remove_recent_sessions (_path);
3738 _current_snapshot_name = new_name;
3741 /* re-add directory separator - reverse hack to oldstr above */
3742 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
3743 _path += G_DIR_SEPARATOR;
3748 /* save state again to get everything just right */
3750 save_state (_current_snapshot_name);
3753 /* add to recent sessions */
3755 store_recent_sessions (new_name, _path);
3761 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3763 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3767 if (!tree.read (xmlpath)) {
3775 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3778 bool found_sr = false;
3779 bool found_data_format = false;
3781 if (get_session_info_from_path (tree, xmlpath)) {
3787 const XMLProperty* prop;
3788 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3789 sample_rate = atoi (prop->value());
3793 const XMLNodeList& children (tree.root()->children());
3794 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3795 const XMLNode* child = *c;
3796 if (child->name() == "Config") {
3797 const XMLNodeList& options (child->children());
3798 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3799 const XMLNode* option = *oc;
3800 const XMLProperty* name = option->property("name");
3806 if (name->value() == "native-file-data-format") {
3807 const XMLProperty* value = option->property ("value");
3809 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3811 found_data_format = true;
3817 if (found_data_format) {
3822 return !(found_sr && found_data_format); // zero if they are both found