Mema
Memory Matrix — multi-channel audio matrix monitor and router
Loading...
Searching...
No Matches
MemaReComponent.cpp
Go to the documentation of this file.
1/* Copyright (c) 2025, Christian Ahrens
2 *
3 * This file is part of Mema <https://github.com/ChristianAhrens/Mema>
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
19#include "MemaReComponent.h"
20
23
25 : juce::Component()
26{
27 m_faderbankCtrlComponent = std::make_unique<Mema::FaderbankControlComponent>();
28 m_faderbankCtrlComponent->onInputMutesChanged = [=](const std::map<std::uint16_t, bool>& inputMuteStates) {
29 std::map<std::uint16_t, bool> outputMuteStates;
30 std::map<std::uint16_t, std::map<std::uint16_t, bool>> crosspointStates;
31 std::map<std::uint16_t, std::map<std::uint16_t, float>> crosspointValues;
33 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
34 };
35 m_faderbankCtrlComponent->onOutputMutesChanged = [=](const std::map<std::uint16_t, bool>& outputMuteStates) {
36 std::map<std::uint16_t, bool> inputMuteStates;
37 std::map<std::uint16_t, std::map<std::uint16_t, bool>> crosspointStates;
38 std::map<std::uint16_t, std::map<std::uint16_t, float>> crosspointValues;
40 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
41 };
42 m_faderbankCtrlComponent->onCrosspointStatesChanged = [=](const std::map<std::uint16_t, std::map<std::uint16_t, bool>>& crosspointStates) {
43 std::map<std::uint16_t, bool> inputMuteStates;
44 std::map<std::uint16_t, bool> outputMuteStates;
45 std::map<std::uint16_t, std::map<std::uint16_t, float>> crosspointValues;
47 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
48 };
49 m_faderbankCtrlComponent->onCrosspointValuesChanged = [=](const std::map<std::uint16_t, std::map<std::uint16_t, float>>& crosspointValues) {
50 std::map<std::uint16_t, bool> inputMuteStates;
51 std::map<std::uint16_t, bool> outputMuteStates;
52 std::map<std::uint16_t, std::map<std::uint16_t, bool>> crosspointStates;
54 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
55 };
56 addChildComponent(m_faderbankCtrlComponent.get());
57
58 m_panningCtrlComponent = std::make_unique<Mema::PanningControlComponent>();
59 m_panningCtrlComponent->onInputMutesChanged = [=](const std::map<std::uint16_t, bool>& inputMuteStates) {
60 std::map<std::uint16_t, bool> outputMuteStates;
61 std::map<std::uint16_t, std::map<std::uint16_t, bool>> crosspointStates;
62 std::map<std::uint16_t, std::map<std::uint16_t, float>> crosspointValues;
64 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
65 };
66 m_panningCtrlComponent->onOutputMutesChanged = [=](const std::map<std::uint16_t, bool>& outputMuteStates) {
67 std::map<std::uint16_t, bool> inputMuteStates;
68 std::map<std::uint16_t, std::map<std::uint16_t, bool>> crosspointStates;
69 std::map<std::uint16_t, std::map<std::uint16_t, float>> crosspointValues;
71 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
72 };
73 m_panningCtrlComponent->onCrosspointStatesChanged = [=](const std::map<std::uint16_t, std::map<std::uint16_t, bool>>& crosspointStates) {
74 std::map<std::uint16_t, bool> inputMuteStates;
75 std::map<std::uint16_t, bool> outputMuteStates;
76 std::map<std::uint16_t, std::map<std::uint16_t, float>> crosspointValues;
78 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
79 };
80 m_panningCtrlComponent->onCrosspointValuesChanged = [=](const std::map<std::uint16_t, std::map<std::uint16_t, float>>& crosspointValues) {
81 std::map<std::uint16_t, bool> inputMuteStates;
82 std::map<std::uint16_t, bool> outputMuteStates;
83 std::map<std::uint16_t, std::map<std::uint16_t, bool>> crosspointStates;
85 onMessageReadyToSend(std::make_unique<Mema::ControlParametersMessage>(inputMuteStates, outputMuteStates, crosspointStates, crosspointValues)->getSerializedMessage());
86 };
87 m_panningCtrlComponent->setExternalControlSettings(std::get<0>(m_externalAdmOscSettings), std::get<1>(m_externalAdmOscSettings), std::get<2>(m_externalAdmOscSettings));
88 addChildComponent(m_panningCtrlComponent.get());
89
90 m_pluginCtrlComponent = std::make_unique<Mema::PluginControlComponent>();
91 m_pluginCtrlComponent->onPluginParameterValueChanged = [=](std::uint16_t parameterIndex, std::string parameterId, float value) {
92 DBG(juce::String(__FUNCTION__) + " sending to net (" + juce::String(parameterIndex) + "; " + juce::String(parameterId) + "; " + juce::String(value) + ") ...");
94 onMessageReadyToSend(std::make_unique<Mema::PluginParameterValueMessage>(parameterIndex, parameterId, value)->getSerializedMessage());
95 };
96 addChildComponent(m_pluginCtrlComponent.get());
97
99}
100
104
106{
107 auto resizeRequired = false;
108
109 if (m_faderbankCtrlComponent)
110 {
111 if (!m_faderbankCtrlComponent->isVisible())
112 {
113 m_faderbankCtrlComponent->setIOCount(m_currentIOCount);
114 m_faderbankCtrlComponent->setVisible(true);
115 resizeRequired = true;
116 }
117 }
118 if (m_panningCtrlComponent && m_panningCtrlComponent->isVisible())
119 {
120 m_panningCtrlComponent->resetCtrl();
121 m_panningCtrlComponent->setVisible(false);
122 resizeRequired = true;
123 }
124 if (m_pluginCtrlComponent && m_pluginCtrlComponent->isVisible())
125 {
126 m_pluginCtrlComponent->resetCtrl();
127 m_pluginCtrlComponent->setVisible(false);
128 resizeRequired = true;
129 }
130
131 if (resizeRequired && !getLocalBounds().isEmpty())
132 resized();
133}
134
135void MemaReComponent::setOutputPanningCtrlActive(const juce::AudioChannelSet& channelConfiguration)
136{
137 auto resizeRequired = false;
138
139 if (m_panningCtrlComponent)
140 {
141 if (!m_panningCtrlComponent->isVisible())
142 {
143 m_panningCtrlComponent->setIOCount(m_currentIOCount);
144 m_panningCtrlComponent->setVisible(true);
145 resizeRequired = true;
146 }
147 m_panningCtrlComponent->setChannelConfig(channelConfiguration);
148 }
149 if (m_faderbankCtrlComponent && m_faderbankCtrlComponent->isVisible())
150 {
151 m_faderbankCtrlComponent->resetCtrl();
152 m_faderbankCtrlComponent->setVisible(false);
153 resizeRequired = true;
154 }
155 if (m_pluginCtrlComponent && m_pluginCtrlComponent->isVisible())
156 {
157 m_pluginCtrlComponent->resetCtrl();
158 m_pluginCtrlComponent->setVisible(false);
159 resizeRequired = true;
160 }
161
162 if (resizeRequired && !getLocalBounds().isEmpty())
163 resized();
164}
165
167{
168 auto resizeRequired = false;
169
170 if (m_pluginCtrlComponent)
171 {
172 if (!m_pluginCtrlComponent->isVisible())
173 {
174 m_pluginCtrlComponent->setVisible(true);
175 resizeRequired = true;
176 }
177 }
178 if (m_faderbankCtrlComponent && m_faderbankCtrlComponent->isVisible())
179 {
180 m_faderbankCtrlComponent->resetCtrl();
181 m_faderbankCtrlComponent->setVisible(false);
182 resizeRequired = true;
183 }
184 if (m_panningCtrlComponent && m_panningCtrlComponent->isVisible())
185 {
186 m_panningCtrlComponent->resetCtrl();
187 m_panningCtrlComponent->setVisible(false);
188 resizeRequired = true;
189 }
190
191 if (resizeRequired && !getLocalBounds().isEmpty())
192 resized();
193}
194
196{
197 if (m_faderbankCtrlComponent)
198 m_faderbankCtrlComponent->resetCtrl();
199 if (m_panningCtrlComponent)
200 m_panningCtrlComponent->resetCtrl();
201 if (m_pluginCtrlComponent)
202 m_pluginCtrlComponent->resetCtrl();
203}
204
206{
207 if (m_faderbankCtrlComponent)
208 m_faderbankCtrlComponent->setControlsSize(ctrlsSize);
209 if (m_panningCtrlComponent)
210 m_panningCtrlComponent->setControlsSize(ctrlsSize);
211 if (m_pluginCtrlComponent)
212 m_pluginCtrlComponent->setControlsSize(ctrlsSize);
213}
214
216{
217 if (m_faderbankCtrlComponent)
218 return m_faderbankCtrlComponent->getControlsSize();
219 else if (m_panningCtrlComponent)
220 return m_panningCtrlComponent->getControlsSize();
221 else if (m_pluginCtrlComponent)
222 return m_pluginCtrlComponent->getControlsSize();
223 else
225}
226
227void MemaReComponent::setExternalAdmOscSettings(const int ADMOSCport, const juce::IPAddress& ADMOSCremoteIP, const int ADMOSCremotePort)
228{
229 std::get<0>(m_externalAdmOscSettings) = ADMOSCport;
230 std::get<1>(m_externalAdmOscSettings) = ADMOSCremoteIP;
231 std::get<2>(m_externalAdmOscSettings) = ADMOSCremotePort;
232
233 m_panningCtrlComponent->setExternalControlSettings(ADMOSCport, ADMOSCremoteIP, ADMOSCremotePort);
234}
235
236std::tuple<int, juce::IPAddress, int> MemaReComponent::getExternalAdmOscSettings()
237{
238 return m_externalAdmOscSettings;
239}
240
241void MemaReComponent::paint(Graphics &g)
242{
243 g.fillAll(getLookAndFeel().findColour(juce::LookAndFeel_V4::ColourScheme::widgetBackground));
244}
245
247{
248 if (m_faderbankCtrlComponent && m_faderbankCtrlComponent->isVisible())
249 m_faderbankCtrlComponent->setBounds(getLocalBounds());
250 if (m_panningCtrlComponent && m_panningCtrlComponent->isVisible())
251 m_panningCtrlComponent->setBounds(getLocalBounds());
252 if (m_pluginCtrlComponent && m_pluginCtrlComponent->isVisible())
253 m_pluginCtrlComponent->setBounds(getLocalBounds());
254}
255
256void MemaReComponent::handleMessage(const Message& message)
257{
258 if (RunningStatus::Active != m_runningStatus)
259 {
260 m_runningStatus = RunningStatus::Active;
261 resized();
262 }
263
264 if (auto const apm = dynamic_cast<const Mema::AnalyzerParametersMessage*>(&message))
265 {
266 // we don't want analyzer parameter infos!
267 DBG(juce::String(__FUNCTION__) + " ignoring unexpected AnalyzerParametersMessage...");
268 }
269 else if (auto m = dynamic_cast<const Mema::AudioBufferMessage*>(&message))
270 {
271 // we don't want audio buffer infos!
272 DBG(juce::String(__FUNCTION__) + " ignoring unexpected AudiBufferMessage...");
273 }
274 else if (auto const iom = dynamic_cast<const Mema::ReinitIOCountMessage*>(&message))
275 {
276 DBG(juce::String(__FUNCTION__) + " handling ReinitIOCountMessage...");
277
278 auto inputCount = iom->getInputCount();
279 jassert(inputCount > 0);
280 auto outputCount = iom->getOutputCount();
281 jassert(outputCount > 0);
282
283 m_currentIOCount = std::make_pair(inputCount, outputCount);
284
285 if (m_faderbankCtrlComponent)
286 m_faderbankCtrlComponent->setIOCount(m_currentIOCount);
287 if (m_panningCtrlComponent)
288 m_panningCtrlComponent->setIOCount(m_currentIOCount);
289
290 resized();
291 }
292 else if (auto const cpm = dynamic_cast<const Mema::ControlParametersMessage*>(&message))
293 {
294 DBG(juce::String(__FUNCTION__) + " handling ControlParametersMessage...");
295
296 for (auto const& inputMuteState : cpm->getInputMuteStates())
297 m_inputMuteStates[inputMuteState.first] = inputMuteState.second;
298 if (!m_inputMuteStates.empty())
299 {
300 if (m_faderbankCtrlComponent)
301 m_faderbankCtrlComponent->setInputMuteStates(m_inputMuteStates);
302 if (m_panningCtrlComponent)
303 m_panningCtrlComponent->setInputMuteStates(m_inputMuteStates);
304 }
305
306 for (auto const& outputMuteState : cpm->getOutputMuteStates())
307 m_outputMuteStates[outputMuteState.first] = outputMuteState.second;
308 if (!m_outputMuteStates.empty())
309 {
310 if (m_faderbankCtrlComponent)
311 m_faderbankCtrlComponent->setOutputMuteStates(m_outputMuteStates);
312 if (m_panningCtrlComponent)
313 m_panningCtrlComponent->setOutputMuteStates(m_outputMuteStates);
314 }
315
316 for (auto const& cpsIKV : cpm->getCrosspointStates())
317 for (auto const& cpsOKV : cpsIKV.second)
318 m_crosspointStates[cpsIKV.first][cpsOKV.first] = cpsOKV.second;
319 if (!m_crosspointStates.empty())
320 {
321 if (m_faderbankCtrlComponent)
322 m_faderbankCtrlComponent->setCrosspointStates(m_crosspointStates);
323 if (m_panningCtrlComponent)
324 m_panningCtrlComponent->setCrosspointStates(m_crosspointStates);
325 }
326
327 for (auto const& cpvIKV : cpm->getCrosspointValues())
328 for (auto const& cpvOKV : cpvIKV.second)
329 m_crosspointValues[cpvIKV.first][cpvOKV.first] = cpvOKV.second;
330 if (!m_crosspointValues.empty())
331 {
332 if (m_faderbankCtrlComponent)
333 m_faderbankCtrlComponent->setCrosspointValues(m_crosspointValues);
334 if (m_panningCtrlComponent)
335 m_panningCtrlComponent->setCrosspointValues(m_crosspointValues);
336 }
337
338 resized();
339 }
340 else if (auto const ppim = dynamic_cast<const Mema::PluginParameterInfosMessage*>(&message))
341 {
342 DBG(juce::String(__FUNCTION__) + " handling PluginParameterInfosMessage (" + juce::String(ppim->getParameterInfos().size()) + ") ...");
343
344 if (m_pluginCtrlComponent && m_pluginCtrlComponent->isVisible())
345 {
346 m_pluginCtrlComponent->setPluginName(ppim->getPluginName().toStdString());
347 m_pluginCtrlComponent->setParameterInfos(ppim->getParameterInfos());
348 }
349
350 resized();
351 }
352 else if (auto const ppvm = dynamic_cast<const Mema::PluginParameterValueMessage*>(&message))
353 {
354 DBG(juce::String(__FUNCTION__) + " handling PluginParameterValueMessage (" + juce::String(ppvm->getParameterIndex()) + "; " + ppvm->getParameterId() + "; " + juce::String(ppvm->getCurrentValue()) + ") ...");
355
356 if (m_pluginCtrlComponent && m_pluginCtrlComponent->isVisible())
357 m_pluginCtrlComponent->setParameterValue(ppvm->getParameterIndex(), ppvm->getParameterId().toStdString(), ppvm->getCurrentValue());
358
359 resized();
360 }
361}
362
~MemaReComponent() override
void resized() override
Lays out the active control component to fill the available area.
const Mema::FaderbankControlComponent::ControlsSize getControlsSize()
Returns the current control-element size setting.
void resetCtrl()
Resets all control components to their default/empty state.
@ Active
Actively receiving and sending control data to/from Mema.
void setOutputPanningCtrlActive(const juce::AudioChannelSet &channelConfiguration)
Switches to the 2-D spatial panning control for the given speaker layout.
void handleMessage(const Message &message) override
Dispatches inbound network messages to the appropriate control component.
void paint(juce::Graphics &g) override
Paints the background when no control mode is active.
void setFaderbankCtrlActive()
Switches to the faderbank (crosspoint slider/mute matrix) control mode.
void setPluginCtrlActive()
Switches to the plugin-parameter control mode.
void setControlsSize(const Mema::FaderbankControlComponent::ControlsSize &ctrlsSize)
Propagates a control-element size change (S/M/L) to the faderbank component.
void setExternalAdmOscSettings(const int ADMOSCport, const juce::IPAddress &ADMOSCremoteIP, const int ADMOSCremotePort)
Configures the ADM-OSC listener port and the remote-controller address used by the panning component.
std::function< void(const juce::MemoryBlock &)> onMessageReadyToSend
Invoked with a serialised message whenever a control value changes that must be sent to Mema.
std::tuple< int, juce::IPAddress, int > getExternalAdmOscSettings()
Returns the current ADM-OSC settings as {listenPort, remoteIP, remotePort}.
Carries audio-device parameters (sample rate, block size) from Mema to clients.
Base message carrying a serialised audio buffer and its flow-direction metadata.
Full routing-matrix state snapshot exchanged bidirectionally between Mema and Mema....
ControlsSize
Size category for rendered control elements.
@ S
Small — suited for desktop with many channels.
Carries the plugin name and complete parameter descriptor list from Mema to Mema.Re clients.
Carries a single normalised plugin parameter value from Mema.Re to Mema.
Instructs clients to tear down and rebuild their UI for a new channel count.