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/localtime_r.h"
77 #include "ardour/amp.h"
78 #include "ardour/async_midi_port.h"
79 #include "ardour/audio_diskstream.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/automation_control.h"
85 #include "ardour/butler.h"
86 #include "ardour/control_protocol_manager.h"
87 #include "ardour/directory_names.h"
88 #include "ardour/filename_extensions.h"
89 #include "ardour/graph.h"
90 #include "ardour/location.h"
91 #include "ardour/midi_model.h"
92 #include "ardour/midi_patch_manager.h"
93 #include "ardour/midi_region.h"
94 #include "ardour/midi_scene_changer.h"
95 #include "ardour/midi_source.h"
96 #include "ardour/midi_track.h"
97 #include "ardour/pannable.h"
98 #include "ardour/playlist_factory.h"
99 #include "ardour/port.h"
100 #include "ardour/processor.h"
101 #include "ardour/proxy_controllable.h"
102 #include "ardour/recent_sessions.h"
103 #include "ardour/region_factory.h"
104 #include "ardour/route_group.h"
105 #include "ardour/send.h"
106 #include "ardour/session.h"
107 #include "ardour/session_directory.h"
108 #include "ardour/session_metadata.h"
109 #include "ardour/session_playlists.h"
110 #include "ardour/session_state_utils.h"
111 #include "ardour/silentfilesource.h"
112 #include "ardour/sndfilesource.h"
113 #include "ardour/source_factory.h"
114 #include "ardour/speakers.h"
115 #include "ardour/template_utils.h"
116 #include "ardour/tempo.h"
117 #include "ardour/ticker.h"
118 #include "ardour/user_bundle.h"
120 #include "control_protocol/control_protocol.h"
126 using namespace ARDOUR;
130 Session::pre_engine_init (string fullpath)
132 if (fullpath.empty()) {
134 throw failed_constructor();
137 /* discover canonical fullpath */
139 _path = canonical_path(fullpath);
141 /* we require _path to end with a dir separator */
143 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
144 _path += G_DIR_SEPARATOR;
149 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
151 /* finish initialization that can't be done in a normal C++ constructor
155 timerclear (&last_mmc_step);
156 g_atomic_int_set (&processing_prohibited, 0);
157 g_atomic_int_set (&_record_status, Disabled);
158 g_atomic_int_set (&_playback_load, 100);
159 g_atomic_int_set (&_capture_load, 100);
161 _all_route_group->set_active (true, this);
162 interpolation.add_channel_to (0, 0);
164 if (config.get_use_video_sync()) {
165 waiting_for_sync_offset = true;
167 waiting_for_sync_offset = false;
170 last_rr_session_dir = session_dirs.begin();
172 set_history_depth (Config->get_history_depth());
174 /* default: assume simple stereo speaker configuration */
176 _speakers->setup_default_speakers (2);
178 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
179 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
180 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
181 add_controllable (_solo_cut_control);
183 /* These are all static "per-class" signals */
185 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
186 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
187 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
188 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
189 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
191 /* stop IO objects from doing stuff until we're ready for them */
193 Delivery::disable_panners ();
194 IO::disable_connecting ();
196 AudioFileSource::set_peak_dir (_session_dir->peak_path());
200 Session::post_engine_init ()
202 BootMessage (_("Set block size and sample rate"));
204 set_block_size (_engine.samples_per_cycle());
205 set_frame_rate (_engine.sample_rate());
207 BootMessage (_("Using configuration"));
209 _midi_ports = new MidiPortManager;
211 MIDISceneChanger* msc;
213 _scene_changer = msc = new MIDISceneChanger (*this);
214 msc->set_input_port (scene_input_port());
215 msc->set_output_port (scene_out());
217 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
218 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
220 setup_midi_machine_control ();
222 if (_butler->start_thread()) {
226 if (start_midi_thread ()) {
230 setup_click_sounds (0);
231 setup_midi_control ();
233 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
234 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
237 /* tempo map requires sample rate knowledge */
239 _tempo_map = new TempoMap (_current_frame_rate);
240 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
242 /* MidiClock requires a tempo map */
244 midi_clock = new MidiClockTicker ();
245 midi_clock->set_session (this);
247 /* crossfades require sample rate knowledge */
249 SndFileSource::setup_standard_crossfades (*this, frame_rate());
250 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
252 AudioDiskstream::allocate_working_buffers();
253 refresh_disk_space ();
255 /* we're finally ready to call set_state() ... all objects have
256 * been created, the engine is running.
260 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
264 // set_state() will call setup_raid_path(), but if it's a new session we need
265 // to call setup_raid_path() here.
266 setup_raid_path (_path);
271 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
272 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
274 Config->map_parameters (ff);
275 config.map_parameters (ft);
277 /* Reset all panners */
279 Delivery::reset_panners ();
281 /* this will cause the CPM to instantiate any protocols that are in use
282 * (or mandatory), which will pass it this Session, and then call
283 * set_state() on each instantiated protocol to match stored state.
286 ControlProtocolManager::instance().set_session (this);
288 /* This must be done after the ControlProtocolManager set_session above,
289 as it will set states for ports which the ControlProtocolManager creates.
292 // XXX set state of MIDI::Port's
293 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
295 /* And this must be done after the MIDI::Manager::set_port_states as
296 * it will try to make connections whose details are loaded by set_port_states.
301 /* Let control protocols know that we are now all connected, so they
302 * could start talking to surfaces if they want to.
305 ControlProtocolManager::instance().midi_connectivity_established ();
307 if (_is_new && !no_auto_connect()) {
308 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
309 auto_connect_master_bus ();
312 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
314 /* update latencies */
316 initialize_latencies ();
318 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
319 _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
321 } catch (AudioEngine::PortRegistrationFailure& err) {
322 /* handle this one in a different way than all others, so that its clear what happened */
323 error << err.what() << endmsg;
329 BootMessage (_("Reset Remote Controls"));
331 // send_full_time_code (0);
332 _engine.transport_locate (0);
334 _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
335 _mmc->send (MIDI::MachineControlCommand (Timecode::Time ()));
337 MIDI::Name::MidiPatchManager::instance().set_session (this);
340 /* initial program change will be delivered later; see ::config_changed() */
342 _state_of_the_state = Clean;
344 Port::set_connecting_blocked (false);
346 DirtyChanged (); /* EMIT SIGNAL */
350 } else if (state_was_pending) {
352 remove_pending_capture_state ();
353 state_was_pending = false;
360 Session::raid_path () const
362 Searchpath raid_search_path;
364 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
365 raid_search_path += (*i).path;
368 return raid_search_path.to_string ();
372 Session::setup_raid_path (string path)
381 session_dirs.clear ();
383 Searchpath search_path(path);
384 Searchpath sound_search_path;
385 Searchpath midi_search_path;
387 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
389 sp.blocks = 0; // not needed
390 session_dirs.push_back (sp);
392 SessionDirectory sdir(sp.path);
394 sound_search_path += sdir.sound_path ();
395 midi_search_path += sdir.midi_path ();
398 // reset the round-robin soundfile path thingie
399 last_rr_session_dir = session_dirs.begin();
403 Session::path_is_within_session (const std::string& path)
405 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
406 if (PBD::path_is_within (i->path, path)) {
414 Session::ensure_subdirs ()
418 dir = session_directory().peak_path();
420 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
421 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
425 dir = session_directory().sound_path();
427 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
428 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
432 dir = session_directory().midi_path();
434 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
435 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
439 dir = session_directory().dead_path();
441 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
442 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
446 dir = session_directory().export_path();
448 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
449 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
453 dir = analysis_dir ();
455 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
456 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
460 dir = plugins_dir ();
462 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
463 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
467 dir = externals_dir ();
469 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
470 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
477 /** @param session_template directory containing session template, or empty.
478 * Caller must not hold process lock.
481 Session::create (const string& session_template, BusProfile* bus_profile)
483 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
484 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
488 if (ensure_subdirs ()) {
492 _writable = exists_and_writable (_path);
494 if (!session_template.empty()) {
495 std::string in_path = session_template_dir_to_file (session_template);
497 ifstream in(in_path.c_str());
500 /* no need to call legalize_for_path() since the string
501 * in session_template is already a legal path name
503 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
505 ofstream out(out_path.c_str());
511 /* Copy plugin state files from template to new session */
512 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
513 copy_files (template_plugins, plugins_dir ());
518 error << string_compose (_("Could not open %1 for writing session template"), out_path)
524 error << string_compose (_("Could not open session template %1 for reading"), in_path)
531 /* set initial start + end point */
533 _state_of_the_state = Clean;
535 /* set up Master Out and Control Out if necessary */
540 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
542 if (bus_profile->master_out_channels) {
543 boost::shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
547 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
548 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
551 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
552 r->input()->ensure_io (count, false, this);
553 r->output()->ensure_io (count, false, this);
559 /* prohibit auto-connect to master, because there isn't one */
560 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
564 add_routes (rl, false, false, false);
567 /* this allows the user to override settings with an environment variable.
570 if (no_auto_connect()) {
571 bus_profile->input_ac = AutoConnectOption (0);
572 bus_profile->output_ac = AutoConnectOption (0);
575 Config->set_input_auto_connect (bus_profile->input_ac);
576 Config->set_output_auto_connect (bus_profile->output_ac);
579 if (Config->get_use_monitor_bus() && bus_profile) {
580 add_monitor_section ();
587 Session::maybe_write_autosave()
589 if (dirty() && record_status() != Recording) {
590 save_state("", true);
595 Session::remove_pending_capture_state ()
597 std::string pending_state_file_path(_session_dir->root_path());
599 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
601 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
603 if (g_remove (pending_state_file_path.c_str()) != 0) {
604 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
605 pending_state_file_path, g_strerror (errno)) << endmsg;
609 /** Rename a state file.
610 * @param old_name Old snapshot name.
611 * @param new_name New snapshot name.
614 Session::rename_state (string old_name, string new_name)
616 if (old_name == _current_snapshot_name || old_name == _name) {
617 /* refuse to rename the current snapshot or the "main" one */
621 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
622 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
624 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
625 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
627 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
628 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
629 old_name, new_name, g_strerror(errno)) << endmsg;
633 /** Remove a state file.
634 * @param snapshot_name Snapshot name.
637 Session::remove_state (string snapshot_name)
639 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
640 // refuse to remove the current snapshot or the "main" one
644 std::string xml_path(_session_dir->root_path());
646 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
648 if (!create_backup_file (xml_path)) {
649 // don't remove it if a backup can't be made
650 // create_backup_file will log the error.
655 if (g_remove (xml_path.c_str()) != 0) {
656 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
657 xml_path, g_strerror (errno)) << endmsg;
661 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
663 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
666 std::string xml_path(_session_dir->root_path());
668 if (!_writable || (_state_of_the_state & CannotSave)) {
672 if (!_engine.connected ()) {
673 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
679 /* tell sources we're saving first, in case they write out to a new file
680 * which should be saved with the state rather than the old one */
681 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
683 i->second->session_saved();
684 } catch (Evoral::SMF::FileError& e) {
685 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
689 SaveSession (); /* EMIT SIGNAL */
691 tree.set_root (&get_state());
693 if (snapshot_name.empty()) {
694 snapshot_name = _current_snapshot_name;
695 } else if (switch_to_snapshot) {
696 _current_snapshot_name = snapshot_name;
701 /* proper save: use statefile_suffix (.ardour in English) */
703 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
705 /* make a backup copy of the old file */
707 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
708 // create_backup_file will log the error
714 /* pending save: use pending_suffix (.pending in English) */
715 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
718 std::string tmp_path(_session_dir->root_path());
719 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
721 // cerr << "actually writing state to " << xml_path << endl;
723 if (!tree.write (tmp_path)) {
724 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
725 if (g_remove (tmp_path.c_str()) != 0) {
726 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
727 tmp_path, g_strerror (errno)) << endmsg;
733 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
734 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
735 tmp_path, xml_path, g_strerror(errno)) << endmsg;
736 if (g_remove (tmp_path.c_str()) != 0) {
737 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
738 tmp_path, g_strerror (errno)) << endmsg;
746 save_history (snapshot_name);
748 bool was_dirty = dirty();
750 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
753 DirtyChanged (); /* EMIT SIGNAL */
756 StateSaved (snapshot_name); /* EMIT SIGNAL */
763 Session::restore_state (string snapshot_name)
765 if (load_state (snapshot_name) == 0) {
766 set_state (*state_tree->root(), Stateful::loading_state_version);
773 Session::load_state (string snapshot_name)
778 state_was_pending = false;
780 /* check for leftover pending state from a crashed capture attempt */
782 std::string xmlpath(_session_dir->root_path());
783 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
785 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
787 /* there is pending state from a crashed capture attempt */
789 boost::optional<int> r = AskAboutPendingState();
790 if (r.get_value_or (1)) {
791 state_was_pending = true;
795 if (!state_was_pending) {
796 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
799 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
800 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
801 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
802 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
807 state_tree = new XMLTree;
811 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
813 if (!state_tree->read (xmlpath)) {
814 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
820 XMLNode& root (*state_tree->root());
822 if (root.name() != X_("Session")) {
823 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
829 const XMLProperty* prop;
831 if ((prop = root.property ("version")) == 0) {
832 /* no version implies very old version of Ardour */
833 Stateful::loading_state_version = 1000;
835 if (prop->value().find ('.') != string::npos) {
836 /* old school version format */
837 if (prop->value()[0] == '2') {
838 Stateful::loading_state_version = 2000;
840 Stateful::loading_state_version = 3000;
843 Stateful::loading_state_version = atoi (prop->value());
847 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
849 std::string backup_path(_session_dir->root_path());
850 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
851 backup_path = Glib::build_filename (backup_path, backup_filename);
853 // only create a backup for a given statefile version once
855 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
857 VersionMismatch (xmlpath, backup_path);
859 if (!copy_file (xmlpath, backup_path)) {;
869 Session::load_options (const XMLNode& node)
871 LocaleGuard lg (X_("POSIX"));
872 config.set_variables (node);
883 Session::get_template()
885 /* if we don't disable rec-enable, diskstreams
886 will believe they need to store their capture
887 sources in their state node.
890 disable_record (false);
896 Session::state (bool full_state)
898 XMLNode* node = new XMLNode("Session");
902 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
903 node->add_property("version", buf);
905 /* store configuration settings */
909 node->add_property ("name", _name);
910 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
911 node->add_property ("sample-rate", buf);
913 if (session_dirs.size() > 1) {
917 vector<space_and_path>::iterator i = session_dirs.begin();
918 vector<space_and_path>::iterator next;
920 ++i; /* skip the first one */
924 while (i != session_dirs.end()) {
928 if (next != session_dirs.end()) {
929 p += G_SEARCHPATH_SEPARATOR;
938 child = node->add_child ("Path");
939 child->add_content (p);
943 /* save the ID counter */
945 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
946 node->add_property ("id-counter", buf);
948 /* save the event ID counter */
950 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
951 node->add_property ("event-counter", buf);
953 /* various options */
955 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
956 if (!midi_port_nodes.empty()) {
957 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
958 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
959 midi_port_stuff->add_child_nocopy (**n);
961 node->add_child_nocopy (*midi_port_stuff);
964 node->add_child_nocopy (config.get_variables ());
966 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
968 child = node->add_child ("Sources");
971 Glib::Threads::Mutex::Lock sl (source_lock);
973 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
975 /* Don't save information about non-file Sources, or
976 * about non-destructive file sources that are empty
977 * and unused by any regions.
980 boost::shared_ptr<FileSource> fs;
982 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
984 if (!fs->destructive()) {
985 if (fs->empty() && !fs->used()) {
990 child->add_child_nocopy (siter->second->get_state());
995 child = node->add_child ("Regions");
998 Glib::Threads::Mutex::Lock rl (region_lock);
999 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1000 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1001 boost::shared_ptr<Region> r = i->second;
1002 /* only store regions not attached to playlists */
1003 if (r->playlist() == 0) {
1004 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1005 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1007 child->add_child_nocopy (r->get_state ());
1012 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1014 if (!cassocs.empty()) {
1015 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1017 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1019 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1020 i->first->id().print (buf, sizeof (buf));
1021 can->add_property (X_("copy"), buf);
1022 i->second->id().print (buf, sizeof (buf));
1023 can->add_property (X_("original"), buf);
1024 ca->add_child_nocopy (*can);
1030 node->add_child_nocopy (_locations->get_state());
1032 // for a template, just create a new Locations, populate it
1033 // with the default start and end, and get the state for that.
1034 Locations loc (*this);
1035 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1036 range->set (max_framepos, 0);
1038 node->add_child_nocopy (loc.get_state());
1041 child = node->add_child ("Bundles");
1043 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1044 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1045 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1047 child->add_child_nocopy (b->get_state());
1052 child = node->add_child ("Routes");
1054 boost::shared_ptr<RouteList> r = routes.reader ();
1056 RoutePublicOrderSorter cmp;
1057 RouteList public_order (*r);
1058 public_order.sort (cmp);
1060 /* the sort should have put control outs first */
1063 assert (_monitor_out == public_order.front());
1066 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1067 if (!(*i)->is_auditioner()) {
1069 child->add_child_nocopy ((*i)->get_state());
1071 child->add_child_nocopy ((*i)->get_template());
1077 playlists->add_state (node, full_state);
1079 child = node->add_child ("RouteGroups");
1080 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1081 child->add_child_nocopy ((*i)->get_state());
1085 XMLNode* gain_child = node->add_child ("Click");
1086 gain_child->add_child_nocopy (_click_io->state (full_state));
1087 gain_child->add_child_nocopy (_click_gain->state (full_state));
1091 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1092 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1096 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1097 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1100 node->add_child_nocopy (_speakers->get_state());
1101 node->add_child_nocopy (_tempo_map->get_state());
1102 node->add_child_nocopy (get_control_protocol_state());
1105 node->add_child_copy (*_extra_xml);
1112 Session::get_control_protocol_state ()
1114 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1115 return cpm.get_state();
1119 Session::set_state (const XMLNode& node, int version)
1123 const XMLProperty* prop;
1126 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1128 if (node.name() != X_("Session")) {
1129 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1133 if ((prop = node.property ("name")) != 0) {
1134 _name = prop->value ();
1137 if ((prop = node.property (X_("sample-rate"))) != 0) {
1139 _nominal_frame_rate = atoi (prop->value());
1141 if (_nominal_frame_rate != _current_frame_rate) {
1142 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1143 if (r.get_value_or (0)) {
1149 setup_raid_path(_session_dir->root_path());
1151 if ((prop = node.property (X_("id-counter"))) != 0) {
1153 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1154 ID::init_counter (x);
1156 /* old sessions used a timebased counter, so fake
1157 the startup ID counter based on a standard
1162 ID::init_counter (now);
1165 if ((prop = node.property (X_("event-counter"))) != 0) {
1166 Evoral::init_event_id_counter (atoi (prop->value()));
1170 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1171 _midi_ports->set_midi_port_states (child->children());
1174 IO::disable_connecting ();
1176 Stateful::save_extra_xml (node);
1178 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1179 load_options (*child);
1180 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1181 load_options (*child);
1183 error << _("Session: XML state has no options section") << endmsg;
1186 if (version >= 3000) {
1187 if ((child = find_named_node (node, "Metadata")) == 0) {
1188 warning << _("Session: XML state has no metadata section") << endmsg;
1189 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1194 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1195 _speakers->set_state (*child, version);
1198 if ((child = find_named_node (node, "Sources")) == 0) {
1199 error << _("Session: XML state has no sources section") << endmsg;
1201 } else if (load_sources (*child)) {
1205 if ((child = find_named_node (node, "TempoMap")) == 0) {
1206 error << _("Session: XML state has no Tempo Map section") << endmsg;
1208 } else if (_tempo_map->set_state (*child, version)) {
1212 if ((child = find_named_node (node, "Locations")) == 0) {
1213 error << _("Session: XML state has no locations section") << endmsg;
1215 } else if (_locations->set_state (*child, version)) {
1221 if ((location = _locations->auto_loop_location()) != 0) {
1222 set_auto_loop_location (location);
1225 if ((location = _locations->auto_punch_location()) != 0) {
1226 set_auto_punch_location (location);
1229 if ((location = _locations->session_range_location()) != 0) {
1230 delete _session_range_location;
1231 _session_range_location = location;
1234 if (_session_range_location) {
1235 AudioFileSource::set_header_position_offset (_session_range_location->start());
1238 if ((child = find_named_node (node, "Regions")) == 0) {
1239 error << _("Session: XML state has no Regions section") << endmsg;
1241 } else if (load_regions (*child)) {
1245 if ((child = find_named_node (node, "Playlists")) == 0) {
1246 error << _("Session: XML state has no playlists section") << endmsg;
1248 } else if (playlists->load (*this, *child)) {
1252 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1254 } else if (playlists->load_unused (*this, *child)) {
1258 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1259 if (load_compounds (*child)) {
1264 if (version >= 3000) {
1265 if ((child = find_named_node (node, "Bundles")) == 0) {
1266 warning << _("Session: XML state has no bundles section") << endmsg;
1269 /* We can't load Bundles yet as they need to be able
1270 to convert from port names to Port objects, which can't happen until
1272 _bundle_xml_node = new XMLNode (*child);
1276 if (version < 3000) {
1277 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1278 error << _("Session: XML state has no diskstreams section") << endmsg;
1280 } else if (load_diskstreams_2X (*child, version)) {
1285 if ((child = find_named_node (node, "Routes")) == 0) {
1286 error << _("Session: XML state has no routes section") << endmsg;
1288 } else if (load_routes (*child, version)) {
1292 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1293 _diskstreams_2X.clear ();
1295 if (version >= 3000) {
1297 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1298 error << _("Session: XML state has no route groups section") << endmsg;
1300 } else if (load_route_groups (*child, version)) {
1304 } else if (version < 3000) {
1306 if ((child = find_named_node (node, "EditGroups")) == 0) {
1307 error << _("Session: XML state has no edit groups section") << endmsg;
1309 } else if (load_route_groups (*child, version)) {
1313 if ((child = find_named_node (node, "MixGroups")) == 0) {
1314 error << _("Session: XML state has no mix groups section") << endmsg;
1316 } else if (load_route_groups (*child, version)) {
1321 if ((child = find_named_node (node, "Click")) == 0) {
1322 warning << _("Session: XML state has no click section") << endmsg;
1323 } else if (_click_io) {
1324 setup_click_state (&node);
1327 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1328 ControlProtocolManager::instance().set_state (*child, version);
1331 update_have_rec_enabled_track ();
1333 /* here beginneth the second phase ... */
1335 StateReady (); /* EMIT SIGNAL */
1344 Session::load_routes (const XMLNode& node, int version)
1347 XMLNodeConstIterator niter;
1348 RouteList new_routes;
1350 nlist = node.children();
1354 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1356 boost::shared_ptr<Route> route;
1357 if (version < 3000) {
1358 route = XMLRouteFactory_2X (**niter, version);
1360 route = XMLRouteFactory (**niter, version);
1364 error << _("Session: cannot create Route from XML description.") << endmsg;
1368 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1370 new_routes.push_back (route);
1373 add_routes (new_routes, false, false, false);
1378 boost::shared_ptr<Route>
1379 Session::XMLRouteFactory (const XMLNode& node, int version)
1381 boost::shared_ptr<Route> ret;
1383 if (node.name() != "Route") {
1387 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1389 DataType type = DataType::AUDIO;
1390 const XMLProperty* prop = node.property("default-type");
1393 type = DataType (prop->value());
1396 assert (type != DataType::NIL);
1400 boost::shared_ptr<Track> track;
1402 if (type == DataType::AUDIO) {
1403 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1405 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1408 if (track->init()) {
1412 if (track->set_state (node, version)) {
1416 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1417 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1422 enum Route::Flag flags = Route::Flag(0);
1423 const XMLProperty* prop = node.property("flags");
1425 flags = Route::Flag (string_2_enum (prop->value(), flags));
1428 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1430 if (r->init () == 0 && r->set_state (node, version) == 0) {
1431 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1432 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1441 boost::shared_ptr<Route>
1442 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1444 boost::shared_ptr<Route> ret;
1446 if (node.name() != "Route") {
1450 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1452 ds_prop = node.property (X_("diskstream"));
1455 DataType type = DataType::AUDIO;
1456 const XMLProperty* prop = node.property("default-type");
1459 type = DataType (prop->value());
1462 assert (type != DataType::NIL);
1466 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1467 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1471 if (i == _diskstreams_2X.end()) {
1472 error << _("Could not find diskstream for route") << endmsg;
1473 return boost::shared_ptr<Route> ();
1476 boost::shared_ptr<Track> track;
1478 if (type == DataType::AUDIO) {
1479 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1481 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1484 if (track->init()) {
1488 if (track->set_state (node, version)) {
1492 track->set_diskstream (*i);
1494 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1495 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1500 enum Route::Flag flags = Route::Flag(0);
1501 const XMLProperty* prop = node.property("flags");
1503 flags = Route::Flag (string_2_enum (prop->value(), flags));
1506 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1508 if (r->init () == 0 && r->set_state (node, version) == 0) {
1509 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1510 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1520 Session::load_regions (const XMLNode& node)
1523 XMLNodeConstIterator niter;
1524 boost::shared_ptr<Region> region;
1526 nlist = node.children();
1530 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1531 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1532 error << _("Session: cannot create Region from XML description.");
1533 const XMLProperty *name = (**niter).property("name");
1536 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1547 Session::load_compounds (const XMLNode& node)
1549 XMLNodeList calist = node.children();
1550 XMLNodeConstIterator caiter;
1551 XMLProperty *caprop;
1553 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1554 XMLNode* ca = *caiter;
1558 if ((caprop = ca->property (X_("original"))) == 0) {
1561 orig_id = caprop->value();
1563 if ((caprop = ca->property (X_("copy"))) == 0) {
1566 copy_id = caprop->value();
1568 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1569 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1571 if (!orig || !copy) {
1572 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1578 RegionFactory::add_compound_association (orig, copy);
1585 Session::load_nested_sources (const XMLNode& node)
1588 XMLNodeConstIterator niter;
1590 nlist = node.children();
1592 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1593 if ((*niter)->name() == "Source") {
1595 /* it may already exist, so don't recreate it unnecessarily
1598 XMLProperty* prop = (*niter)->property (X_("id"));
1600 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1604 ID source_id (prop->value());
1606 if (!source_by_id (source_id)) {
1609 SourceFactory::create (*this, **niter, true);
1611 catch (failed_constructor& err) {
1612 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1619 boost::shared_ptr<Region>
1620 Session::XMLRegionFactory (const XMLNode& node, bool full)
1622 const XMLProperty* type = node.property("type");
1626 const XMLNodeList& nlist = node.children();
1628 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1629 XMLNode *child = (*niter);
1630 if (child->name() == "NestedSource") {
1631 load_nested_sources (*child);
1635 if (!type || type->value() == "audio") {
1636 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1637 } else if (type->value() == "midi") {
1638 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1641 } catch (failed_constructor& err) {
1642 return boost::shared_ptr<Region> ();
1645 return boost::shared_ptr<Region> ();
1648 boost::shared_ptr<AudioRegion>
1649 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1651 const XMLProperty* prop;
1652 boost::shared_ptr<Source> source;
1653 boost::shared_ptr<AudioSource> as;
1655 SourceList master_sources;
1656 uint32_t nchans = 1;
1659 if (node.name() != X_("Region")) {
1660 return boost::shared_ptr<AudioRegion>();
1663 if ((prop = node.property (X_("channels"))) != 0) {
1664 nchans = atoi (prop->value().c_str());
1667 if ((prop = node.property ("name")) == 0) {
1668 cerr << "no name for this region\n";
1672 if ((prop = node.property (X_("source-0"))) == 0) {
1673 if ((prop = node.property ("source")) == 0) {
1674 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1675 return boost::shared_ptr<AudioRegion>();
1679 PBD::ID s_id (prop->value());
1681 if ((source = source_by_id (s_id)) == 0) {
1682 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1683 return boost::shared_ptr<AudioRegion>();
1686 as = boost::dynamic_pointer_cast<AudioSource>(source);
1688 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1689 return boost::shared_ptr<AudioRegion>();
1692 sources.push_back (as);
1694 /* pickup other channels */
1696 for (uint32_t n=1; n < nchans; ++n) {
1697 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1698 if ((prop = node.property (buf)) != 0) {
1700 PBD::ID id2 (prop->value());
1702 if ((source = source_by_id (id2)) == 0) {
1703 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1704 return boost::shared_ptr<AudioRegion>();
1707 as = boost::dynamic_pointer_cast<AudioSource>(source);
1709 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1710 return boost::shared_ptr<AudioRegion>();
1712 sources.push_back (as);
1716 for (uint32_t n = 0; n < nchans; ++n) {
1717 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1718 if ((prop = node.property (buf)) != 0) {
1720 PBD::ID id2 (prop->value());
1722 if ((source = source_by_id (id2)) == 0) {
1723 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1724 return boost::shared_ptr<AudioRegion>();
1727 as = boost::dynamic_pointer_cast<AudioSource>(source);
1729 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1730 return boost::shared_ptr<AudioRegion>();
1732 master_sources.push_back (as);
1737 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1739 /* a final detail: this is the one and only place that we know how long missing files are */
1741 if (region->whole_file()) {
1742 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1743 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1745 sfp->set_length (region->length());
1750 if (!master_sources.empty()) {
1751 if (master_sources.size() != nchans) {
1752 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1754 region->set_master_sources (master_sources);
1762 catch (failed_constructor& err) {
1763 return boost::shared_ptr<AudioRegion>();
1767 boost::shared_ptr<MidiRegion>
1768 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1770 const XMLProperty* prop;
1771 boost::shared_ptr<Source> source;
1772 boost::shared_ptr<MidiSource> ms;
1775 if (node.name() != X_("Region")) {
1776 return boost::shared_ptr<MidiRegion>();
1779 if ((prop = node.property ("name")) == 0) {
1780 cerr << "no name for this region\n";
1784 if ((prop = node.property (X_("source-0"))) == 0) {
1785 if ((prop = node.property ("source")) == 0) {
1786 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1787 return boost::shared_ptr<MidiRegion>();
1791 PBD::ID s_id (prop->value());
1793 if ((source = source_by_id (s_id)) == 0) {
1794 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1795 return boost::shared_ptr<MidiRegion>();
1798 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1800 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1801 return boost::shared_ptr<MidiRegion>();
1804 sources.push_back (ms);
1807 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1808 /* a final detail: this is the one and only place that we know how long missing files are */
1810 if (region->whole_file()) {
1811 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1812 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1814 sfp->set_length (region->length());
1822 catch (failed_constructor& err) {
1823 return boost::shared_ptr<MidiRegion>();
1828 Session::get_sources_as_xml ()
1831 XMLNode* node = new XMLNode (X_("Sources"));
1832 Glib::Threads::Mutex::Lock lm (source_lock);
1834 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1835 node->add_child_nocopy (i->second->get_state());
1842 Session::path_from_region_name (DataType type, string name, string identifier)
1844 char buf[PATH_MAX+1];
1846 SessionDirectory sdir(get_best_session_directory_for_new_source());
1847 std::string source_dir = ((type == DataType::AUDIO)
1848 ? sdir.sound_path() : sdir.midi_path());
1850 string ext = native_header_format_extension (config.get_native_file_header_format(), type);
1852 for (n = 0; n < 999999; ++n) {
1853 if (identifier.length()) {
1854 snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
1855 identifier.c_str(), n, ext.c_str());
1857 snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
1861 std::string source_path = Glib::build_filename (source_dir, buf);
1863 if (!Glib::file_test (source_path, Glib::FILE_TEST_EXISTS)) {
1868 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1877 Session::load_sources (const XMLNode& node)
1880 XMLNodeConstIterator niter;
1881 boost::shared_ptr<Source> source;
1883 nlist = node.children();
1887 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1890 if ((source = XMLSourceFactory (**niter)) == 0) {
1891 error << _("Session: cannot create Source from XML description.") << endmsg;
1894 } catch (MissingSource& err) {
1898 if (!no_questions_about_missing_files) {
1899 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1904 switch (user_choice) {
1906 /* user added a new search location, so try again */
1911 /* user asked to quit the entire session load
1916 no_questions_about_missing_files = true;
1920 no_questions_about_missing_files = true;
1925 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1926 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1935 boost::shared_ptr<Source>
1936 Session::XMLSourceFactory (const XMLNode& node)
1938 if (node.name() != "Source") {
1939 return boost::shared_ptr<Source>();
1943 /* note: do peak building in another thread when loading session state */
1944 return SourceFactory::create (*this, node, true);
1947 catch (failed_constructor& err) {
1948 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
1949 return boost::shared_ptr<Source>();
1954 Session::save_template (string template_name)
1958 if (_state_of_the_state & CannotSave) {
1962 std::string user_template_dir(user_template_directory());
1964 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
1965 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
1966 user_template_dir, g_strerror (errno)) << endmsg;
1970 tree.set_root (&get_template());
1972 std::string template_dir_path(user_template_dir);
1974 /* directory to put the template in */
1975 template_dir_path = Glib::build_filename (template_dir_path, template_name);
1977 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
1978 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
1979 template_dir_path) << endmsg;
1983 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
1984 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
1985 template_dir_path, g_strerror (errno)) << endmsg;
1990 std::string template_file_path(template_dir_path);
1991 template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
1993 if (!tree.write (template_file_path)) {
1994 error << _("template not saved") << endmsg;
1998 /* copy plugin state directory */
2000 std::string template_plugin_state_path(template_dir_path);
2001 template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
2003 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2004 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2005 template_plugin_state_path, g_strerror (errno)) << endmsg;
2009 copy_files (plugins_dir(), template_plugin_state_path);
2015 Session::refresh_disk_space ()
2017 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2019 Glib::Threads::Mutex::Lock lm (space_lock);
2021 /* get freespace on every FS that is part of the session path */
2023 _total_free_4k_blocks = 0;
2024 _total_free_4k_blocks_uncertain = false;
2026 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2028 struct statfs statfsbuf;
2029 statfs (i->path.c_str(), &statfsbuf);
2031 double const scale = statfsbuf.f_bsize / 4096.0;
2033 /* See if this filesystem is read-only */
2034 struct statvfs statvfsbuf;
2035 statvfs (i->path.c_str(), &statvfsbuf);
2037 /* f_bavail can be 0 if it is undefined for whatever
2038 filesystem we are looking at; Samba shares mounted
2039 via GVFS are an example of this.
2041 if (statfsbuf.f_bavail == 0) {
2042 /* block count unknown */
2044 i->blocks_unknown = true;
2045 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2046 /* read-only filesystem */
2048 i->blocks_unknown = false;
2050 /* read/write filesystem with known space */
2051 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2052 i->blocks_unknown = false;
2055 _total_free_4k_blocks += i->blocks;
2056 if (i->blocks_unknown) {
2057 _total_free_4k_blocks_uncertain = true;
2060 #elif defined (COMPILER_MSVC)
2061 vector<string> scanned_volumes;
2062 vector<string>::iterator j;
2063 vector<space_and_path>::iterator i;
2064 DWORD nSectorsPerCluster, nBytesPerSector,
2065 nFreeClusters, nTotalClusters;
2069 _total_free_4k_blocks = 0;
2071 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2072 strncpy (disk_drive, (*i).path.c_str(), 3);
2076 volume_found = false;
2077 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2079 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2080 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2081 i->blocks = (uint32_t)(nFreeBytes / 4096);
2083 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2084 if (0 == j->compare(disk_drive)) {
2085 volume_found = true;
2090 if (!volume_found) {
2091 scanned_volumes.push_back(disk_drive);
2092 _total_free_4k_blocks += i->blocks;
2097 if (0 == _total_free_4k_blocks) {
2098 strncpy (disk_drive, path().c_str(), 3);
2101 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2103 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2104 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2105 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2112 Session::get_best_session_directory_for_new_source ()
2114 vector<space_and_path>::iterator i;
2115 string result = _session_dir->root_path();
2117 /* handle common case without system calls */
2119 if (session_dirs.size() == 1) {
2123 /* OK, here's the algorithm we're following here:
2125 We want to select which directory to use for
2126 the next file source to be created. Ideally,
2127 we'd like to use a round-robin process so as to
2128 get maximum performance benefits from splitting
2129 the files across multiple disks.
2131 However, in situations without much diskspace, an
2132 RR approach may end up filling up a filesystem
2133 with new files while others still have space.
2134 Its therefore important to pay some attention to
2135 the freespace in the filesystem holding each
2136 directory as well. However, if we did that by
2137 itself, we'd keep creating new files in the file
2138 system with the most space until it was as full
2139 as all others, thus negating any performance
2140 benefits of this RAID-1 like approach.
2142 So, we use a user-configurable space threshold. If
2143 there are at least 2 filesystems with more than this
2144 much space available, we use RR selection between them.
2145 If not, then we pick the filesystem with the most space.
2147 This gets a good balance between the two
2151 refresh_disk_space ();
2153 int free_enough = 0;
2155 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2156 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2161 if (free_enough >= 2) {
2162 /* use RR selection process, ensuring that the one
2166 i = last_rr_session_dir;
2169 if (++i == session_dirs.end()) {
2170 i = session_dirs.begin();
2173 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2174 SessionDirectory sdir(i->path);
2175 if (sdir.create ()) {
2177 last_rr_session_dir = i;
2182 } while (i != last_rr_session_dir);
2186 /* pick FS with the most freespace (and that
2187 seems to actually work ...)
2190 vector<space_and_path> sorted;
2191 space_and_path_ascending_cmp cmp;
2193 sorted = session_dirs;
2194 sort (sorted.begin(), sorted.end(), cmp);
2196 for (i = sorted.begin(); i != sorted.end(); ++i) {
2197 SessionDirectory sdir(i->path);
2198 if (sdir.create ()) {
2200 last_rr_session_dir = i;
2210 Session::automation_dir () const
2212 return Glib::build_filename (_path, "automation");
2216 Session::analysis_dir () const
2218 return Glib::build_filename (_path, "analysis");
2222 Session::plugins_dir () const
2224 return Glib::build_filename (_path, "plugins");
2228 Session::externals_dir () const
2230 return Glib::build_filename (_path, "externals");
2234 Session::load_bundles (XMLNode const & node)
2236 XMLNodeList nlist = node.children();
2237 XMLNodeConstIterator niter;
2241 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2242 if ((*niter)->name() == "InputBundle") {
2243 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2244 } else if ((*niter)->name() == "OutputBundle") {
2245 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2247 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2256 Session::load_route_groups (const XMLNode& node, int version)
2258 XMLNodeList nlist = node.children();
2259 XMLNodeConstIterator niter;
2263 if (version >= 3000) {
2265 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2266 if ((*niter)->name() == "RouteGroup") {
2267 RouteGroup* rg = new RouteGroup (*this, "");
2268 add_route_group (rg);
2269 rg->set_state (**niter, version);
2273 } else if (version < 3000) {
2275 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2276 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2277 RouteGroup* rg = new RouteGroup (*this, "");
2278 add_route_group (rg);
2279 rg->set_state (**niter, version);
2288 Session::auto_save()
2290 save_state (_current_snapshot_name);
2294 state_file_filter (const string &str, void* /*arg*/)
2296 return (str.length() > strlen(statefile_suffix) &&
2297 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2301 remove_end(string state)
2303 string statename(state);
2305 string::size_type start,end;
2306 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2307 statename = statename.substr (start+1);
2310 if ((end = statename.rfind(".ardour")) == string::npos) {
2311 end = statename.length();
2314 return string(statename.substr (0, end));
2318 Session::possible_states (string path)
2320 vector<string> states;
2321 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2323 transform(states.begin(), states.end(), states.begin(), remove_end);
2325 sort (states.begin(), states.end());
2331 Session::possible_states () const
2333 return possible_states(_path);
2337 Session::add_route_group (RouteGroup* g)
2339 _route_groups.push_back (g);
2340 route_group_added (g); /* EMIT SIGNAL */
2342 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2343 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2344 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2350 Session::remove_route_group (RouteGroup& rg)
2352 list<RouteGroup*>::iterator i;
2354 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2355 _route_groups.erase (i);
2358 route_group_removed (); /* EMIT SIGNAL */
2362 /** Set a new order for our route groups, without adding or removing any.
2363 * @param groups Route group list in the new order.
2366 Session::reorder_route_groups (list<RouteGroup*> groups)
2368 _route_groups = groups;
2370 route_groups_reordered (); /* EMIT SIGNAL */
2376 Session::route_group_by_name (string name)
2378 list<RouteGroup *>::iterator i;
2380 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2381 if ((*i)->name() == name) {
2389 Session::all_route_group() const
2391 return *_all_route_group;
2395 Session::add_commands (vector<Command*> const & cmds)
2397 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2403 Session::begin_reversible_command (const string& name)
2405 begin_reversible_command (g_quark_from_string (name.c_str ()));
2408 /** Begin a reversible command using a GQuark to identify it.
2409 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2410 * but there must be as many begin...()s as there are commit...()s.
2413 Session::begin_reversible_command (GQuark q)
2415 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2416 to hold all the commands that are committed. This keeps the order of
2417 commands correct in the history.
2420 if (_current_trans == 0) {
2421 /* start a new transaction */
2422 assert (_current_trans_quarks.empty ());
2423 _current_trans = new UndoTransaction();
2424 _current_trans->set_name (g_quark_to_string (q));
2427 _current_trans_quarks.push_front (q);
2431 Session::commit_reversible_command (Command *cmd)
2433 assert (_current_trans);
2434 assert (!_current_trans_quarks.empty ());
2439 _current_trans->add_command (cmd);
2442 _current_trans_quarks.pop_front ();
2444 if (!_current_trans_quarks.empty ()) {
2445 /* the transaction we're committing is not the top-level one */
2449 if (_current_trans->empty()) {
2450 /* no commands were added to the transaction, so just get rid of it */
2451 delete _current_trans;
2456 gettimeofday (&now, 0);
2457 _current_trans->set_timestamp (now);
2459 _history.add (_current_trans);
2464 accept_all_audio_files (const string& path, void* /*arg*/)
2466 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2470 if (!AudioFileSource::safe_audio_file_extension (path)) {
2478 accept_all_midi_files (const string& path, void* /*arg*/)
2480 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2484 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2485 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2486 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2490 accept_all_state_files (const string& path, void* /*arg*/)
2492 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2496 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2500 Session::find_all_sources (string path, set<string>& result)
2505 if (!tree.read (path)) {
2509 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2514 XMLNodeConstIterator niter;
2516 nlist = node->children();
2520 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2524 if ((prop = (*niter)->property (X_("type"))) == 0) {
2528 DataType type (prop->value());
2530 if ((prop = (*niter)->property (X_("name"))) == 0) {
2534 if (Glib::path_is_absolute (prop->value())) {
2535 /* external file, ignore */
2543 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2544 result.insert (found_path);
2552 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2554 vector<string> state_files;
2556 string this_snapshot_path;
2562 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2563 ripped = ripped.substr (0, ripped.length() - 1);
2566 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2568 if (state_files.empty()) {
2573 this_snapshot_path = _path;
2574 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2575 this_snapshot_path += statefile_suffix;
2577 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2579 if (exclude_this_snapshot && *i == this_snapshot_path) {
2583 if (find_all_sources (*i, result) < 0) {
2591 struct RegionCounter {
2592 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2593 AudioSourceList::iterator iter;
2594 boost::shared_ptr<Region> region;
2597 RegionCounter() : count (0) {}
2601 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2603 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2604 return r.get_value_or (1);
2608 Session::cleanup_regions ()
2610 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2612 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2614 uint32_t used = playlists->region_use_count (i->second);
2616 if (used == 0 && !i->second->automatic ()) {
2617 RegionFactory::map_remove (i->second);
2621 /* dump the history list */
2628 Session::cleanup_sources (CleanupReport& rep)
2630 // FIXME: needs adaptation to midi
2632 vector<boost::shared_ptr<Source> > dead_sources;
2635 vector<space_and_path>::iterator i;
2636 vector<space_and_path>::iterator nexti;
2637 vector<string> candidates;
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 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2720 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2722 /* find all sources, but don't use this snapshot because the
2723 state file on disk still references sources we may have already
2727 find_all_sources_across_snapshots (all_sources, true);
2729 /* add our current source list
2732 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2733 boost::shared_ptr<FileSource> fs;
2734 SourceMap::iterator tmp = i;
2737 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2739 if (!fs->is_stub()) {
2741 if (playlists->source_use_count (fs) != 0) {
2742 all_sources.insert (fs->path());
2745 /* we might not remove this source from disk, because it may be used
2746 by other snapshots, but its not being used in this version
2747 so lets get rid of it now, along with any representative regions
2751 RegionFactory::remove_regions_using_source (i->second);
2760 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2765 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2767 tmppath1 = canonical_path (spath);
2768 tmppath2 = canonical_path ((*i));
2770 if (tmppath1 == tmppath2) {
2777 unused.push_back (spath);
2781 /* now try to move all unused files into the "dead" directory(ies) */
2783 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2784 struct stat statbuf;
2788 /* don't move the file across filesystems, just
2789 stick it in the `dead_dir_name' directory
2790 on whichever filesystem it was already on.
2793 if ((*x).find ("/sounds/") != string::npos) {
2795 /* old school, go up 1 level */
2797 newpath = Glib::path_get_dirname (*x); // "sounds"
2798 newpath = Glib::path_get_dirname (newpath); // "session-name"
2802 /* new school, go up 4 levels */
2804 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2805 newpath = Glib::path_get_dirname (newpath); // "session-name"
2806 newpath = Glib::path_get_dirname (newpath); // "interchange"
2807 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2810 newpath = Glib::build_filename (newpath, dead_dir_name);
2812 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2813 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2817 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2819 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2821 /* the new path already exists, try versioning */
2823 char buf[PATH_MAX+1];
2827 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2830 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2831 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2835 if (version == 999) {
2836 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2840 newpath = newpath_v;
2845 /* it doesn't exist, or we can't read it or something */
2849 stat ((*x).c_str(), &statbuf);
2851 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2852 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2853 (*x), newpath, strerror (errno))
2858 /* see if there an easy to find peakfile for this file, and remove it.
2861 string base = basename_nosuffix (*x);
2862 base += "%A"; /* this is what we add for the channel suffix of all native files,
2863 or for the first channel of embedded files. it will miss
2864 some peakfiles for other channels
2866 string peakpath = peak_path (base);
2868 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2869 if (::g_unlink (peakpath.c_str()) != 0) {
2870 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2871 peakpath, _path, strerror (errno))
2873 /* try to back out */
2874 ::rename (newpath.c_str(), _path.c_str());
2879 rep.paths.push_back (*x);
2880 rep.space += statbuf.st_size;
2883 /* dump the history list */
2887 /* save state so we don't end up a session file
2888 referring to non-existent sources.
2895 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2901 Session::cleanup_trash_sources (CleanupReport& rep)
2903 // FIXME: needs adaptation for MIDI
2905 vector<space_and_path>::iterator i;
2911 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2913 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
2915 clear_directory (dead_dir, &rep.space, &rep.paths);
2922 Session::set_dirty ()
2924 bool was_dirty = dirty();
2926 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2930 DirtyChanged(); /* EMIT SIGNAL */
2936 Session::set_clean ()
2938 bool was_dirty = dirty();
2940 _state_of_the_state = Clean;
2944 DirtyChanged(); /* EMIT SIGNAL */
2949 Session::set_deletion_in_progress ()
2951 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2955 Session::clear_deletion_in_progress ()
2957 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2961 Session::add_controllable (boost::shared_ptr<Controllable> c)
2963 /* this adds a controllable to the list managed by the Session.
2964 this is a subset of those managed by the Controllable class
2965 itself, and represents the only ones whose state will be saved
2966 as part of the session.
2969 Glib::Threads::Mutex::Lock lm (controllables_lock);
2970 controllables.insert (c);
2973 struct null_deleter { void operator()(void const *) const {} };
2976 Session::remove_controllable (Controllable* c)
2978 if (_state_of_the_state & Deletion) {
2982 Glib::Threads::Mutex::Lock lm (controllables_lock);
2984 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
2986 if (x != controllables.end()) {
2987 controllables.erase (x);
2991 boost::shared_ptr<Controllable>
2992 Session::controllable_by_id (const PBD::ID& id)
2994 Glib::Threads::Mutex::Lock lm (controllables_lock);
2996 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
2997 if ((*i)->id() == id) {
3002 return boost::shared_ptr<Controllable>();
3005 boost::shared_ptr<Controllable>
3006 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3008 boost::shared_ptr<Controllable> c;
3009 boost::shared_ptr<Route> r;
3011 switch (desc.top_level_type()) {
3012 case ControllableDescriptor::NamedRoute:
3014 std::string str = desc.top_level_name();
3015 if (str == "master") {
3017 } else if (str == "control" || str == "listen") {
3020 r = route_by_name (desc.top_level_name());
3025 case ControllableDescriptor::RemoteControlID:
3026 r = route_by_remote_id (desc.rid());
3034 switch (desc.subtype()) {
3035 case ControllableDescriptor::Gain:
3036 c = r->gain_control ();
3039 case ControllableDescriptor::Solo:
3040 c = r->solo_control();
3043 case ControllableDescriptor::Mute:
3044 c = r->mute_control();
3047 case ControllableDescriptor::Recenable:
3049 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3052 c = t->rec_enable_control ();
3057 case ControllableDescriptor::PanDirection:
3059 c = r->pannable()->pan_azimuth_control;
3063 case ControllableDescriptor::PanWidth:
3065 c = r->pannable()->pan_width_control;
3069 case ControllableDescriptor::PanElevation:
3071 c = r->pannable()->pan_elevation_control;
3075 case ControllableDescriptor::Balance:
3076 /* XXX simple pan control */
3079 case ControllableDescriptor::PluginParameter:
3081 uint32_t plugin = desc.target (0);
3082 uint32_t parameter_index = desc.target (1);
3084 /* revert to zero based counting */
3090 if (parameter_index > 0) {
3094 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3097 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3098 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3103 case ControllableDescriptor::SendGain:
3105 uint32_t send = desc.target (0);
3107 /* revert to zero-based counting */
3113 boost::shared_ptr<Processor> p = r->nth_send (send);
3116 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3117 boost::shared_ptr<Amp> a = s->amp();
3120 c = s->amp()->gain_control();
3127 /* relax and return a null pointer */
3135 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3138 Stateful::add_instant_xml (node, _path);
3141 if (write_to_config) {
3142 Config->add_instant_xml (node);
3147 Session::instant_xml (const string& node_name)
3149 return Stateful::instant_xml (node_name, _path);
3153 Session::save_history (string snapshot_name)
3161 if (snapshot_name.empty()) {
3162 snapshot_name = _current_snapshot_name;
3165 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3166 const string backup_filename = history_filename + backup_suffix;
3167 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3168 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3170 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3171 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3172 error << _("could not backup old history file, current history not saved") << endmsg;
3177 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
3181 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3183 if (!tree.write (xml_path))
3185 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3187 if (g_remove (xml_path.c_str()) != 0) {
3188 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3189 xml_path, g_strerror (errno)) << endmsg;
3191 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3192 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3193 backup_path, g_strerror (errno)) << endmsg;
3203 Session::restore_history (string snapshot_name)
3207 if (snapshot_name.empty()) {
3208 snapshot_name = _current_snapshot_name;
3211 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3212 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3214 info << "Loading history from " << xml_path << endmsg;
3216 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3217 info << string_compose (_("%1: no history file \"%2\" for this session."),
3218 _name, xml_path) << endmsg;
3222 if (!tree.read (xml_path)) {
3223 error << string_compose (_("Could not understand session history file \"%1\""),
3224 xml_path) << endmsg;
3231 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3234 UndoTransaction* ut = new UndoTransaction ();
3237 ut->set_name(t->property("name")->value());
3238 stringstream ss(t->property("tv-sec")->value());
3240 ss.str(t->property("tv-usec")->value());
3242 ut->set_timestamp(tv);
3244 for (XMLNodeConstIterator child_it = t->children().begin();
3245 child_it != t->children().end(); child_it++)
3247 XMLNode *n = *child_it;
3250 if (n->name() == "MementoCommand" ||
3251 n->name() == "MementoUndoCommand" ||
3252 n->name() == "MementoRedoCommand") {
3254 if ((c = memento_command_factory(n))) {
3258 } else if (n->name() == "NoteDiffCommand") {
3259 PBD::ID id (n->property("midi-source")->value());
3260 boost::shared_ptr<MidiSource> midi_source =
3261 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3263 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3265 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3268 } else if (n->name() == "SysExDiffCommand") {
3270 PBD::ID id (n->property("midi-source")->value());
3271 boost::shared_ptr<MidiSource> midi_source =
3272 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3274 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3276 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3279 } else if (n->name() == "PatchChangeDiffCommand") {
3281 PBD::ID id (n->property("midi-source")->value());
3282 boost::shared_ptr<MidiSource> midi_source =
3283 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3285 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3287 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3290 } else if (n->name() == "StatefulDiffCommand") {
3291 if ((c = stateful_diff_command_factory (n))) {
3292 ut->add_command (c);
3295 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3306 Session::config_changed (std::string p, bool ours)
3312 if (p == "seamless-loop") {
3314 } else if (p == "rf-speed") {
3316 } else if (p == "auto-loop") {
3318 } else if (p == "auto-input") {
3320 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3321 /* auto-input only makes a difference if we're rolling */
3322 set_track_monitor_input_status (!config.get_auto_input());
3325 } else if (p == "punch-in") {
3329 if ((location = _locations->auto_punch_location()) != 0) {
3331 if (config.get_punch_in ()) {
3332 replace_event (SessionEvent::PunchIn, location->start());
3334 remove_event (location->start(), SessionEvent::PunchIn);
3338 } else if (p == "punch-out") {
3342 if ((location = _locations->auto_punch_location()) != 0) {
3344 if (config.get_punch_out()) {
3345 replace_event (SessionEvent::PunchOut, location->end());
3347 clear_events (SessionEvent::PunchOut);
3351 } else if (p == "edit-mode") {
3353 Glib::Threads::Mutex::Lock lm (playlists->lock);
3355 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3356 (*i)->set_edit_mode (Config->get_edit_mode ());
3359 } else if (p == "use-video-sync") {
3361 waiting_for_sync_offset = config.get_use_video_sync();
3363 } else if (p == "mmc-control") {
3365 //poke_midi_thread ();
3367 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3369 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3371 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3373 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3375 } else if (p == "midi-control") {
3377 //poke_midi_thread ();
3379 } else if (p == "raid-path") {
3381 setup_raid_path (config.get_raid_path());
3383 } else if (p == "timecode-format") {
3387 } else if (p == "video-pullup") {
3391 } else if (p == "seamless-loop") {
3393 if (play_loop && transport_rolling()) {
3394 // to reset diskstreams etc
3395 request_play_loop (true);
3398 } else if (p == "rf-speed") {
3400 cumulative_rf_motion = 0;
3403 } else if (p == "click-sound") {
3405 setup_click_sounds (1);
3407 } else if (p == "click-emphasis-sound") {
3409 setup_click_sounds (-1);
3411 } else if (p == "clicking") {
3413 if (Config->get_clicking()) {
3414 if (_click_io && click_data) { // don't require emphasis data
3421 } else if (p == "click-gain") {
3424 _click_gain->set_gain (Config->get_click_gain(), this);
3427 } else if (p == "send-mtc") {
3429 if (Config->get_send_mtc ()) {
3430 /* mark us ready to send */
3431 next_quarter_frame_to_send = 0;
3434 } else if (p == "send-mmc") {
3436 _mmc->enable_send (Config->get_send_mmc ());
3438 } else if (p == "midi-feedback") {
3440 session_midi_feedback = Config->get_midi_feedback();
3442 } else if (p == "jack-time-master") {
3444 engine().reset_timebase ();
3446 } else if (p == "native-file-header-format") {
3448 if (!first_file_header_format_reset) {
3449 reset_native_file_format ();
3452 first_file_header_format_reset = false;
3454 } else if (p == "native-file-data-format") {
3456 if (!first_file_data_format_reset) {
3457 reset_native_file_format ();
3460 first_file_data_format_reset = false;
3462 } else if (p == "external-sync") {
3463 if (!config.get_external_sync()) {
3464 drop_sync_source ();
3466 switch_to_sync_source (Config->get_sync_source());
3468 } else if (p == "denormal-model") {
3470 } else if (p == "history-depth") {
3471 set_history_depth (Config->get_history_depth());
3472 } else if (p == "remote-model") {
3473 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3476 } else if (p == "initial-program-change") {
3478 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3481 buf[0] = MIDI::program; // channel zero by default
3482 buf[1] = (Config->get_initial_program_change() & 0x7f);
3484 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3486 } else if (p == "solo-mute-override") {
3487 // catch_up_on_solo_mute_override ();
3488 } else if (p == "listen-position" || p == "pfl-position") {
3489 listen_position_changed ();
3490 } else if (p == "solo-control-is-listen-control") {
3491 solo_control_mode_changed ();
3492 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3493 last_timecode_valid = false;
3494 } else if (p == "playback-buffer-seconds") {
3495 AudioSource::allocate_working_buffers (frame_rate());
3496 } else if (p == "automation-thinning-factor") {
3497 Evoral::ControlList::set_thinning_factor (Config->get_automation_thinning_factor());
3498 } else if (p == "ltc-source-port") {
3499 reconnect_ltc_input ();
3500 } else if (p == "ltc-sink-port") {
3501 reconnect_ltc_output ();
3502 } else if (p == "timecode-generator-offset") {
3503 ltc_tx_parse_offset();
3510 Session::set_history_depth (uint32_t d)
3512 _history.set_depth (d);
3516 Session::load_diskstreams_2X (XMLNode const & node, int)
3519 XMLNodeConstIterator citer;
3521 clist = node.children();
3523 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3526 /* diskstreams added automatically by DiskstreamCreated handler */
3527 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3528 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3529 _diskstreams_2X.push_back (dsp);
3531 error << _("Session: unknown diskstream type in XML") << endmsg;
3535 catch (failed_constructor& err) {
3536 error << _("Session: could not load diskstream via XML state") << endmsg;
3544 /** Connect things to the MMC object */
3546 Session::setup_midi_machine_control ()
3548 _mmc = new MIDI::MachineControl;
3549 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3551 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3552 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3553 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3554 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3555 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3556 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3557 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3558 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3559 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3560 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3561 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3562 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3563 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3565 /* also handle MIDI SPP because its so common */
3567 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3568 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3569 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3572 boost::shared_ptr<Controllable>
3573 Session::solo_cut_control() const
3575 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3576 controls in Ardour that currently get presented to the user in the GUI that require
3577 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3579 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3580 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3584 return _solo_cut_control;
3588 Session::rename (const std::string& new_name)
3590 string legal_name = legalize_for_path (new_name);
3596 string const old_sources_root = _session_dir->sources_root();
3601 * interchange subdirectory
3605 * Backup files are left unchanged and not renamed.
3608 /* pass one: not 100% safe check that the new directory names don't
3612 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3617 /* this is a stupid hack because Glib::path_get_dirname() is
3618 * lexical-only, and so passing it /a/b/c/ gives a different
3619 * result than passing it /a/b/c ...
3622 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3623 oldstr = oldstr.substr (0, oldstr.length() - 1);
3626 string base = Glib::path_get_dirname (oldstr);
3627 string p = Glib::path_get_basename (oldstr);
3629 newstr = Glib::build_filename (base, legal_name);
3631 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3638 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3643 /* this is a stupid hack because Glib::path_get_dirname() is
3644 * lexical-only, and so passing it /a/b/c/ gives a different
3645 * result than passing it /a/b/c ...
3648 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3649 oldstr = oldstr.substr (0, oldstr.length() - 1);
3652 string base = Glib::path_get_dirname (oldstr);
3653 string p = Glib::path_get_basename (oldstr);
3655 newstr = Glib::build_filename (base, legal_name);
3657 cerr << "Rename " << oldstr << " => " << newstr << endl;
3659 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3660 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3665 (*_session_dir) = newstr;
3670 /* directory below interchange */
3672 v.push_back (newstr);
3673 v.push_back (interchange_dir_name);
3676 oldstr = Glib::build_filename (v);
3679 v.push_back (newstr);
3680 v.push_back (interchange_dir_name);
3681 v.push_back (legal_name);
3683 newstr = Glib::build_filename (v);
3685 cerr << "Rename " << oldstr << " => " << newstr << endl;
3687 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3688 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3695 oldstr = Glib::build_filename (newpath, _current_snapshot_name) + statefile_suffix;
3696 newstr= Glib::build_filename (newpath, legal_name) + statefile_suffix;
3698 cerr << "Rename " << oldstr << " => " << newstr << endl;
3700 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3701 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3708 oldstr = Glib::build_filename (newpath, _current_snapshot_name) + history_suffix;
3710 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3711 newstr = Glib::build_filename (newpath, legal_name) + history_suffix;
3713 cerr << "Rename " << oldstr << " => " << newstr << endl;
3715 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3716 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3721 /* update file source paths */
3723 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3724 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3726 string p = fs->path ();
3727 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3732 /* remove old name from recent sessions */
3734 remove_recent_sessions (_path);
3737 _current_snapshot_name = new_name;
3740 /* re-add directory separator - reverse hack to oldstr above */
3741 if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
3742 _path += G_DIR_SEPARATOR;
3747 /* save state again to get everything just right */
3749 save_state (_current_snapshot_name);
3752 /* add to recent sessions */
3754 store_recent_sessions (new_name, _path);
3760 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3762 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3766 if (!tree.read (xmlpath)) {
3774 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3777 bool found_sr = false;
3778 bool found_data_format = false;
3780 if (get_session_info_from_path (tree, xmlpath)) {
3786 const XMLProperty* prop;
3787 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3788 sample_rate = atoi (prop->value());
3792 const XMLNodeList& children (tree.root()->children());
3793 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3794 const XMLNode* child = *c;
3795 if (child->name() == "Config") {
3796 const XMLNodeList& options (child->children());
3797 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3798 const XMLNode* option = *oc;
3799 const XMLProperty* name = option->property("name");
3805 if (name->value() == "native-file-data-format") {
3806 const XMLProperty* value = option->property ("value");
3808 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3810 found_data_format = true;
3816 if (found_data_format) {
3821 return !(found_sr && found_data_format); // zero if they are both found