+
+/** @return Path to the config.xml containing the actual settings, following a link if required */
+boost::filesystem::path
+Config::config_file ()
+{
+ cxml::Document f ("Config");
+ auto main = path("config.xml", false);
+ if (!boost::filesystem::exists (main)) {
+ /* It doesn't exist, so there can't be any links; just return it */
+ return main;
+ }
+
+ /* See if there's a link */
+ try {
+ f.read_file (main);
+ auto link = f.optional_string_child("Link");
+ if (link) {
+ return *link;
+ }
+ } catch (xmlpp::exception& e) {
+ /* There as a problem reading the main configuration file,
+ so there can't be a link.
+ */
+ }
+
+ return main;
+}
+
+void
+Config::reset_cover_sheet ()
+{
+ set_cover_sheet_to_default ();
+ changed ();
+}
+
+void
+Config::link (boost::filesystem::path new_file) const
+{
+ xmlpp::Document doc;
+ doc.create_root_node("Config")->add_child("Link")->add_child_text(new_file.string());
+ try {
+ doc.write_to_file_formatted(path("config.xml", true).string());
+ } catch (xmlpp::exception& e) {
+ string s = e.what ();
+ trim (s);
+ throw FileError (s, path("config.xml"));
+ }
+}
+
+void
+Config::copy_and_link (boost::filesystem::path new_file) const
+{
+ write ();
+ boost::filesystem::copy_file (config_file(), new_file, boost::filesystem::copy_option::overwrite_if_exists);
+ link (new_file);
+}
+
+bool
+Config::have_write_permission () const
+{
+ auto f = fopen_boost (config_file(), "r+");
+ if (!f) {
+ return false;
+ }
+
+ fclose (f);
+ return true;
+}
+
+/** @param output_channels Number of output channels in use.
+ * @return Audio mapping for this output channel count (may be a default).
+ */
+AudioMapping
+Config::audio_mapping (int output_channels)
+{
+ if (!_audio_mapping || _audio_mapping->output_channels() != output_channels) {
+ /* Set up a default */
+ _audio_mapping = AudioMapping (MAX_DCP_AUDIO_CHANNELS, output_channels);
+ if (output_channels == 2) {
+ /* Special case for stereo output.
+ Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
+ Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
+ */
+ _audio_mapping->set (dcp::Channel::LEFT, 0, 1 / sqrt(2)); // L -> Lt
+ _audio_mapping->set (dcp::Channel::RIGHT, 1, 1 / sqrt(2)); // R -> Rt
+ _audio_mapping->set (dcp::Channel::CENTRE, 0, 1 / 2.0); // C -> Lt
+ _audio_mapping->set (dcp::Channel::CENTRE, 1, 1 / 2.0); // C -> Rt
+ _audio_mapping->set (dcp::Channel::LFE, 0, 1 / sqrt(10)); // Lfe -> Lt
+ _audio_mapping->set (dcp::Channel::LFE, 1, 1 / sqrt(10)); // Lfe -> Rt
+ _audio_mapping->set (dcp::Channel::LS, 0, 1 / sqrt(2)); // Ls -> Lt
+ _audio_mapping->set (dcp::Channel::RS, 1, 1 / sqrt(2)); // Rs -> Rt
+ } else {
+ /* 1:1 mapping */
+ for (int i = 0; i < min (MAX_DCP_AUDIO_CHANNELS, output_channels); ++i) {
+ _audio_mapping->set (i, i, 1);
+ }
+ }
+ }
+
+ return *_audio_mapping;
+}
+
+void
+Config::set_audio_mapping (AudioMapping m)
+{
+ _audio_mapping = m;
+ changed (AUDIO_MAPPING);
+}
+
+void
+Config::set_audio_mapping_to_default ()
+{
+ DCPOMATIC_ASSERT (_audio_mapping);
+ auto const ch = _audio_mapping->output_channels ();
+ _audio_mapping = boost::none;
+ _audio_mapping = audio_mapping (ch);
+ changed (AUDIO_MAPPING);
+}