24#include <WebUpdateDetector.h>
30JUCE_IMPLEMENT_SINGLETON(
Mema)
36 m_config = std::make_unique<MemaAppConfiguration>(JUCEAppBasics::AppConfigurationBase::getDefaultConfigFilePath());
37 m_config->addDumper(
this);
40 if (!m_config->isValid())
42 m_config->ResetToDefault();
46 m_config->addWatcher(
this,
true);
50 m_audioDeviceSelectComponent = std::make_unique<AudioSelectComponent>(m_MemaProcessor->getDeviceManager(),
55 false,
false,
false,
false);
56 m_audioDeviceSelectComponent->onAudioDeviceChangedDuringAudioSelection = [=]() {
58 m_MemaProcessor->initializeCtrlValuesToUnity();
62 m_config->triggerWatcherUpdate();
69#elif defined JUCE_ANDROID
74#if defined IGNORE_UPDATES
76 auto noUpdates = juce::JUCEApplication::getInstance()->getCommandLineParameters().contains(
"--noupdates");
79 auto updater = JUCEAppBasics::WebUpdateDetector::getInstance();
80 updater->SetReferenceVersion(ProjectInfo::versionString);
81 updater->SetDownloadUpdateWebAddress(
"https://github.com/christianahrens/mema/releases/latest");
82 updater->CheckForNewVersion(
true,
"https://raw.githubusercontent.com/ChristianAhrens/Mema/refs/heads/main/");
90 m_MemaProcessor->editorBeingDeleted(m_MemaProcessor->getActiveEditor());
95 if (m_MemaProcessor && m_MemaProcessor->getDeviceManager())
98 onCpuUsageUpdate(
int(m_MemaProcessor->getDeviceManager()->getCpuUsage() * 100.0));
99 if (onNetworkUsageUpdate)
100 onNetworkUsageUpdate(m_MemaProcessor->getNetworkHealth());
101 if (onServiceDiscoveryTopologyUpdate)
102 onServiceDiscoveryTopologyUpdate(m_MemaProcessor->getDiscoveredServicesTopology());
110 if (
nullptr == m_MemaProcessor->getActiveEditor())
111 m_MemaProcessor->createEditorIfNeeded();
115 jassert(onEditorSizeChangeRequested);
116 editor->onEditorSizeChangeRequested = onEditorSizeChangeRequested;
119 m_MemaProcessor->updateCommanders();
121 return m_MemaProcessor->getActiveEditor();
129 if (m_audioDeviceSelectComponent)
130 return m_audioDeviceSelectComponent.get();
137 return m_MemaProcessor;
142 onEditorSizeChangeRequested =
nullptr;
143 onCpuUsageUpdate =
nullptr;
144 onNetworkUsageUpdate =
nullptr;
145 onServiceDiscoveryTopologyUpdate =
nullptr;
148 editor->onEditorSizeChangeRequested =
nullptr;
155 auto stateXml = m_config->getConfigState();
160 if (m_MemaUIConfigCache)
169 if (processorConfigState && m_MemaProcessor)
171 m_MemaProcessor->setStateXml(processorConfigState.get());
175 if (uiConfigState && m_MemaProcessor)
177 m_MemaUIConfigCache = std::make_unique<juce::XmlElement>(*uiConfigState);
185 m_MemaProcessor->environmentChanged();
189 editor->lookAndFeelChanged();
196 m_MemaUIConfigCache = std::make_unique<juce::XmlElement>(*uiConfigState);
201 return m_MemaUIConfigCache;
206 m_loadSavefileChooser = std::make_unique<juce::FileChooser>(
207 "Please select the " + juce::JUCEApplication::getInstance()->getApplicationName() +
" configuration file you want to load...",
208 juce::File::getSpecialLocation(juce::File::userHomeDirectory),
211 m_loadSavefileChooser->launchAsync(juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles,
212 [=](
const juce::FileChooser& chooser) {
213 juce::File sourceFile(chooser.getResult());
215 if (!sourceFile.existsAsFile() || !sourceFile.hasReadAccess())
217 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
218 .withIconType(juce::MessageBoxIconType::WarningIcon)
219 .withTitle(
"Loading failed")
220 .withMessage(
"The file " + sourceFile.getFileName() +
" cannot be accessed for reading.")
221 .withButton(
"Ok"),
nullptr);
225 auto config = MemaAppConfiguration::getInstance();
228 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
229 .withIconType(juce::MessageBoxIconType::WarningIcon)
230 .withTitle(
"Loading failed")
231 .withMessage(
"There was an internal error with the configuration.")
232 .withButton(
"Ok"),
nullptr);
236 auto xmlConfig = juce::parseXML(sourceFile);
239 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
240 .withIconType(juce::MessageBoxIconType::WarningIcon)
241 .withTitle(
"Loading failed")
242 .withMessage(
"The file " + sourceFile.getFileName() +
" has invalid contents.")
243 .withButton(
"Ok"),
nullptr);
249 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
250 .withIconType(juce::MessageBoxIconType::WarningIcon)
251 .withTitle(
"Loading failed")
252 .withMessage(
"The file " + sourceFile.getFileName() +
" has invalid contents.")
253 .withButton(
"Ok"),
nullptr);
257 config->SetFlushAndUpdateDisabled();
258 if (!config->resetConfigState(std::move(xmlConfig)))
260 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
261 .withIconType(juce::MessageBoxIconType::WarningIcon)
262 .withTitle(
"Loading failed")
263 .withMessage(
"There was an internal error with applying the configuration.")
264 .withButton(
"Ok"),
nullptr);
265 config->ResetFlushAndUpdateDisabled();
268 config->ResetFlushAndUpdateDisabled();
276 m_loadSavefileChooser = std::make_unique<juce::FileChooser>(
277 "Please select the " + juce::JUCEApplication::getInstance()->getApplicationName() +
" configuration file target you want to save to...",
278 juce::File::getSpecialLocation(juce::File::userHomeDirectory).getChildFile(
279 juce::Time::getCurrentTime().toISO8601(
true).substring(0, 10) +
"_" +
280 juce::JUCEApplication::getInstance()->getApplicationName() +
".config"),
283 m_loadSavefileChooser->launchAsync(juce::FileBrowserComponent::saveMode | juce::FileBrowserComponent::canSelectFiles,
284 [=](
const juce::FileChooser& chooser) {
285 juce::File targetFile(chooser.getResult());
288 if (targetFile.getFileExtension() !=
".config")
289 targetFile = targetFile.withFileExtension(
".config");
291 if (!targetFile.hasWriteAccess())
293 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
294 .withIconType(juce::MessageBoxIconType::WarningIcon)
295 .withTitle(
"Saving failed")
296 .withMessage(
"The file " + targetFile.getFileName() +
" cannot be accessed for writing.")
297 .withButton(
"Ok"),
nullptr);
301 auto config = MemaAppConfiguration::getInstance();
304 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
305 .withIconType(juce::MessageBoxIconType::WarningIcon)
306 .withTitle(
"Saving failed")
307 .withMessage(
"There was an internal error with the configuration (0x0).")
308 .withButton(
"Ok"),
nullptr);
312 auto xmlConfig = config->getConfigState();
315 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
316 .withIconType(juce::MessageBoxIconType::WarningIcon)
317 .withTitle(
"Saving failed")
318 .withMessage(
"There was an internal error with the configuration (0x1).")
319 .withButton(
"Ok"),
nullptr);
322 else if (!xmlConfig->writeTo(targetFile))
324 juce::AlertWindow::showAsync(juce::MessageBoxOptions()
325 .withIconType(juce::MessageBoxIconType::WarningIcon)
326 .withTitle(
"Saving failed")
327 .withMessage(
"There was an error when writing the configuration to disk.")
328 .withButton(
"Ok"),
nullptr);
static juce::String getTagName(TagID ID)
@ PROCESSORCONFIG
Audio processor settings.
@ UICONFIG
UI layout and appearance.
bool isValid() override
Returns true when the loaded XML contains all required configuration nodes.
Top-level editor component for the Mema processor — composes the input, crosspoint,...
static constexpr int s_maxChannelCount
Maximum number of input or output channels supported by the routing matrix.
static constexpr int s_minOutputsCount
Minimum number of output channels (always at least 1).
static constexpr int s_minInputsCount
Minimum number of input channels (always at least 1).
void timerCallback() override
Periodic timer callback used to poll CPU usage and trigger deferred dumps.
const std::unique_ptr< MemaProcessor > & getMemaProcessor() const
Provides read access to the owned MemaProcessor instance.
void setUIConfigState(const std::unique_ptr< juce::XmlElement > &uiConfigState)
Stores a UI configuration state snapshot.
void triggerPromptSaveConfig()
Opens a file chooser dialog to save the configuration file.
void performConfigurationDump() override
Serializes the current configuration to file.
juce::Component * getMemaProcessorEditor()
Returns the main processor editor component.
juce::Component * getDeviceSetupComponent()
Returns the audio device setup component.
void clearUICallbacks()
Clears all UI callback functions.
const std::unique_ptr< juce::XmlElement > & getUIConfigState()
Returns the cached UI configuration state.
void triggerPromptLoadConfig()
Opens a file chooser dialog to load a configuration file.
void onConfigUpdated() override
Reacts to configuration changes and updates internal state.
void propagateLookAndFeelChanged()
Propagates a look-and-feel change to all owned components.