Umsci
Upmix Spatial Control Interface — OCA/OCP.1 spatial audio utility
Loading...
Searching...
No Matches
UmsciAppConfiguration.cpp
Go to the documentation of this file.
1/* Copyright (c) 2026, Christian Ahrens
2 *
3 * This file is part of Umsci <https://github.com/ChristianAhrens/Umsci>
4 *
5 * This tool is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3.0 as published
7 * by the Free Software Foundation.
8 *
9 * This tool is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this tool; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
20
21
23 : JUCEAppBasics::AppConfigurationBase()
24{
25 InitializeBase(file, JUCEAppBasics::AppConfigurationBase::Version::FromString(Umsci_CONFIG_VERSION));
26}
27
31
33{
34 return isValid(m_xml);
35}
36
37bool UmsciAppConfiguration::isValid(const std::unique_ptr<juce::XmlElement>& xmlConfig)
38{
39 if (!JUCEAppBasics::AppConfigurationBase::isValid(xmlConfig))
40 return false;
41
42 auto connectionConfigSectionElement = xmlConfig->getChildByName(UmsciAppConfiguration::getTagName(UmsciAppConfiguration::TagID::CONNECTIONCONFIG));
43 if (connectionConfigSectionElement)
44 {
45 if (juce::String("ERROR") == connectionConfigSectionElement->getStringAttribute(UmsciAppConfiguration::getAttributeName(UmsciAppConfiguration::AttributeID::IP), "ERROR"))
46 return false;
47 if (-1 == connectionConfigSectionElement->getIntAttribute(UmsciAppConfiguration::getAttributeName(UmsciAppConfiguration::AttributeID::PORT), -1))
48 return false;
49
50 // positive validation outcome - continue
51 }
52 else
53 return false;
54
55 auto visuConfigSectionElement = xmlConfig->getChildByName(UmsciAppConfiguration::getTagName(UmsciAppConfiguration::TagID::VISUCONFIG));
56 if (visuConfigSectionElement)
57 {
58 auto controlColourXmlElement = visuConfigSectionElement->getChildByName(UmsciAppConfiguration::getTagName(UmsciAppConfiguration::TagID::CONTROLCOLOUR));
59 if (controlColourXmlElement)
60 {
61 // validate
62 }
63 else
64 return false;
65
66 auto lookAndFeelXmlElement = visuConfigSectionElement->getChildByName(UmsciAppConfiguration::getTagName(UmsciAppConfiguration::TagID::LOOKANDFEEL));
67 if (lookAndFeelXmlElement)
68 {
69 // validate
70 }
71 else
72 return false;
73 }
74 else
75 return false;
76
77 auto controlConfigSectionElement = xmlConfig->getChildByName(UmsciAppConfiguration::getTagName(UmsciAppConfiguration::TagID::CONTROLCONFIG));
78 if (controlConfigSectionElement)
79 {
80 if (juce::String("ERROR") == controlConfigSectionElement->getStringAttribute(UmsciAppConfiguration::getAttributeName(UmsciAppConfiguration::AttributeID::IOSIZE), "ERROR"))
81 return false;
82
83 // positive validation outcome - continue
84 }
85 else
86 return false;
87
88 auto upmixConfigSectionElement = xmlConfig->getChildByName(UmsciAppConfiguration::getTagName(UmsciAppConfiguration::TagID::UPMIXCONFIG));
89 if (upmixConfigSectionElement)
90 {
91 if (-1 == upmixConfigSectionElement->getIntAttribute(UmsciAppConfiguration::getAttributeName(UmsciAppConfiguration::AttributeID::UPMIXSOURCESTARTID), -1))
92 return false;
93 if (-1 == upmixConfigSectionElement->getIntAttribute(UmsciAppConfiguration::getAttributeName(UmsciAppConfiguration::AttributeID::UPMIXLIVEMODE), -1))
94 return false;
95 if (juce::String("ERROR") == upmixConfigSectionElement->getStringAttribute(UmsciAppConfiguration::getAttributeName(UmsciAppConfiguration::AttributeID::UPMIXSHAPE), "ERROR"))
96 return false;
97
98 // positive validation outcome - continue
99 }
100 else
101 return false;
102
103 return true;
104}
105
107{
108 auto xmlConfig = juce::parseXML(juce::String(BinaryData::UmsciDefault_config, BinaryData::UmsciDefault_configSize));
109 if (xmlConfig)
110 {
111
112 if (UmsciAppConfiguration::isValid(xmlConfig))
113 {
114
115 SetFlushAndUpdateDisabled();
116 if (resetConfigState(std::move(xmlConfig)))
117 {
118 ResetFlushAndUpdateDisabled();
119 return true;
120 }
121 else
122 {
123 jassertfalse; // stop here when debugging, since invalid configurations often lead to endless debugging sessions until this simple explanation was found...
124 ResetFlushAndUpdateDisabled();
125
126 // ...and trigger generation of a valid config if not.
127 triggerConfigurationDump();
128 }
129 }
130 else
131 {
132 jassertfalse; // stop here when debugging, since invalid configurations often lead to endless debugging sessions until this simple explanation was found...
133
134 // ...and trigger generation of a valid config if not.
135 triggerConfigurationDump();
136 }
137 }
138 else
139 {
140 jassertfalse; // stop here when debugging, since invalid configurations often lead to endless debugging sessions until this simple explanation was found...
141
142 // ...and trigger generation of a valid config if not.
143 triggerConfigurationDump();
144 }
145
146 return false;
147}
148
149bool UmsciAppConfiguration::HandleConfigVersionConflict(const JUCEAppBasics::AppConfigurationBase::Version& configVersionFound)
150{
151 if (configVersionFound != JUCEAppBasics::AppConfigurationBase::Version::FromString(Umsci_CONFIG_VERSION))
152 {
153 auto conflictTitle = "Incompatible configuration version";
154 auto conflictInfo = "The configuration file version detected\ncannot be handled by this version of " + juce::JUCEApplication::getInstance()->getApplicationName();
155#ifdef DEBUG
156 conflictInfo << "\n(Found " + configVersionFound.ToString() + ", expected " + Umsci_CONFIG_VERSION + ")";
157#endif
158 juce::AlertWindow::showOkCancelBox(juce::MessageBoxIconType::WarningIcon, conflictTitle, conflictInfo, "Reset to default", "Quit", nullptr, juce::ModalCallbackFunction::create([this](int result) {
159 if (1 == result)
160 {
162 }
163 else
164 {
165 juce::JUCEApplication::getInstance()->quit();
166 }
167 }));
168
169 return false;
170 }
171 else
172 return true;
173}
174
#define Umsci_CONFIG_VERSION
bool isValid() override
Returns true if the XML file exists and contains the expected root tags.
@ IP
String: target device IP address.
@ UPMIXLIVEMODE
Boolean: follow live DS100 source positions.
@ UPMIXSHAPE
String: "Circle" or "Rectangle".
@ IOSIZE
String: "inputs,outputs" channel count pair.
@ PORT
Integer: target OCP.1 port (default 50014).
@ UPMIXSOURCESTARTID
Integer: 1-based first DS100 channel for upmix inputs.
bool HandleConfigVersionConflict(const Version &configVersionFound) override
Called by the base class when the config file's version string does not match Umsci_CONFIG_VERSION....
bool ResetToDefault()
Overwrites all settings with built-in defaults and triggers a dump.
UmsciAppConfiguration(const File &file)
static juce::String getTagName(TagID ID)
static juce::String getAttributeName(AttributeID ID)
@ CONTROLCONFIG
Control-component settings.
@ CONNECTIONCONFIG
OCP.1 connection parameters.
@ CONTROLCOLOUR
Source/speaker icon colour.
@ LOOKANDFEEL
Look-and-feel variant.
@ UPMIXCONFIG
Upmix behaviour settings.
@ VISUCONFIG
Visual appearance settings.