Mema
Memory Matrix — multi-channel audio matrix monitor and router
Loading...
Searching...
No Matches
ADMOSController.h
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#pragma once
20
21#include <JuceHeader.h>
22
23
24namespace Mema
25{
26
27
35class ADMOSController : public juce::OSCReceiver::Listener<juce::OSCReceiver::RealtimeCallback>, public juce::MessageListener
36{
37public:
39 {
40 None, // change should only be cached and not forwarded in any way
41 Internal, // change is to be sent from this app/process to outside world
42 External, // change was received from outside world and is to be distributed internally
43 };
56 {
57 ADMOSCParameter() = default;
59 type = std::uint16_t(t);
60 switch (type)
61 {
68 break;
71 break;
74 break;
76 default:
78 jassertfalse;
79 break;
80 }
81 };
82
84 std::uint16_t parameterCount = 0;
85 std::uint32_t parameter1 = 0;
86 std::uint32_t parameter2 = 0;
87 std::uint32_t parameter3 = 0;
88 };
90 {
97 parameter1 = other.parameter1;
98 parameter2 = 0;
99 parameter3 = 0;
100 };
102 std::memcpy(&parameter1, &xVal, sizeof(parameter1));
103 };
105 float val;
106 std::memcpy(&val, &parameter1, sizeof(val));
107 return val;
108 };
109 };
111 {
118 parameter1 = 0;
119 parameter2 = other.parameter2;
120 parameter3 = 0;
121 };
123 std::memcpy(&parameter2, &yVal, sizeof(parameter2));
124 };
126 float val;
127 std::memcpy(&val, &parameter2, sizeof(val));
128 return val;
129 };
130 };
132 {
138 jassert(ADMOSCParameterType::Z == other.type || ADMOSCParameterType::XYZ == other.type);
139 parameter1 = 0;
140 parameter2 = 0;
141 parameter3 = other.parameter3;
142 };
144 std::memcpy(&parameter3, &zVal, sizeof(parameter3));
145 };
147 float val;
148 std::memcpy(&val, &parameter3, sizeof(val));
149 return val;
150 };
151 };
153 {
159 jassert(ADMOSCParameterType::XY == other.type || ADMOSCParameterType::XYZ == other.type);
160 parameter1 = other.parameter1;
161 parameter2 = other.parameter2;
162 parameter3 = 0;
163 };
164 ADMOSCParameterXY(float xVal, float yVal) : ADMOSCParameterXY() {
165 std::memcpy(&parameter1, &xVal, sizeof(parameter1));
166 std::memcpy(&parameter2, &yVal, sizeof(parameter2));
167 };
168 std::tuple<float, float> getParameterVals() {
169 std::tuple<float, float> val;
170 std::memcpy(&std::get<0>(val), &parameter1, sizeof(std::get<0>(val)));
171 std::memcpy(&std::get<1>(val), &parameter2, sizeof(std::get<1>(val)));
172 return val;
173 };
174 };
176 {
182 jassert(ADMOSCParameterType::XYZ == other.type);
183 parameter1 = other.parameter1;
184 parameter2 = other.parameter2;
185 parameter3 = other.parameter3;
186 };
187 ADMOSCParameterXYZ(float xVal, float yVal, float zVal) : ADMOSCParameterXYZ() {
188 std::memcpy(&parameter1, &xVal, sizeof(parameter1));
189 std::memcpy(&parameter2, &yVal, sizeof(parameter2));
190 std::memcpy(&parameter3, &zVal, sizeof(parameter3));
191 };
192 std::tuple<float, float, float> getParameterVals() {
193 std::tuple<float, float, float> val;
194 std::memcpy(&std::get<0>(val), &parameter1, sizeof(std::get<0>(val)));
195 std::memcpy(&std::get<1>(val), &parameter2, sizeof(std::get<1>(val)));
196 std::memcpy(&std::get<2>(val), &parameter3, sizeof(std::get<2>(val)));
197 return val;
198 };
199 };
201 {
207 jassert(ADMOSCParameterType::Width == other.type);
208 parameter1 = other.parameter1;
209 parameter2 = 0;
210 parameter3 = 0;
211 };
213 std::memcpy(&parameter1, &width, sizeof(parameter1));
214 };
216 float val;
217 std::memcpy(&val, &parameter1, sizeof(val));
218 return val;
219 };
220 };
222 {
228 jassert(ADMOSCParameterType::Mute == other.type);
229 parameter1 = other.parameter1;
230 parameter2 = 0;
231 parameter3 = 0;
232 };
234 parameter1 = mute ? 1 : 0;
235 };
237 parameter1 = mute01;
238 };
239 bool getParameterVal() { return 1 == parameter1 ? true : false; };
240 int getParameterVal01() { return int(parameter1); };
241 };
242
243 class ADMOSCParameterChangedMessage : public juce::Message
244 {
245 public:
246 ADMOSCParameterChangedMessage(int objNum, std::uint16_t type, ADMOSCParameterChangeTarget target)
247 {
248 m_objNum = objNum;
249 m_type = type;
250 m_target = target;
251
252 std::lock_guard<std::mutex> l(m_typeMapMutex);
253 auto iter = std::find(m_typeMap[objNum].begin(), m_typeMap[objNum].end(), type);
254 if (iter == m_typeMap[objNum].end())
255 m_typeMap[objNum].push_back(type);
256 };
258 {
259 std::lock_guard<std::mutex> l(m_typeMapMutex);
260 auto iter = std::find(m_typeMap[m_objNum].begin(), m_typeMap[m_objNum].end(), m_type);
261 jassert(iter != m_typeMap[m_objNum].end()); // must exist while this instance exists, otherwise something was messed up regarding creation/destruction!
262 if (iter != m_typeMap[m_objNum].end())
263 m_typeMap[m_objNum].erase(iter);
264 };
265
266 static bool createAndPostIfNotAlreadyPending(int objNum, std::uint16_t type, ADMOSCParameterChangeTarget target, ADMOSController* postTarget)
267 {
268 bool isAlreadyPending = false;
269 {
270 std::lock_guard<std::mutex> l(m_typeMapMutex);
271 auto iter = std::find(m_typeMap[objNum].begin(), m_typeMap[objNum].end(), type);
272 if (iter != m_typeMap[objNum].end())
273 isAlreadyPending = true;
274 }
275
276 if (!isAlreadyPending)
277 {
278 postTarget->postMessage(std::make_unique<ADMOSCParameterChangedMessage>(objNum, type, target).release());
279 return true;
280 }
281 else
282 return false;
283 };
284
285 int getObjNum() const
286 {
287 return m_objNum;
288 };
289 std::uint16_t getType() const
290 {
291 return m_type;
292 };
294 {
295 return m_target;
296 };
297
298 private:
299 static std::mutex m_typeMapMutex;
300 static std::map<int, std::vector<std::uint16_t>> m_typeMap;
301
302 int m_objNum;
303 std::uint16_t m_type;
305 };
306
307public:
310
311 bool startConnection(int oscPort, juce::IPAddress targetIP, int targetPort);
312
313 void setNumObjects(int numObjects);
314
315 void setParameter(int objNum, const ADMOSCParameter& param, const ADMOSCParameterChangeTarget& pct = ADMOSCParameterChangeTarget::None);
316 ADMOSCParameter getParameter(int objNum, std::uint16_t type);
317
318 //==============================================================================
319 void oscMessageReceived (const juce::OSCMessage& message) override;
320 void oscBundleReceived(const juce::OSCBundle& bundle) override;
321
322 //==============================================================================
323 void handleMessage(const Message& message) override;
324
325 //==============================================================================
326 std::function<void(int, std::uint16_t)> onParameterChanged;
327
328protected:
329 //==============================================================================
330 const std::vector<int> getObjNumsFromObjIdent(const juce::String& objIdent);
331
332 bool sendParameterChange(int objNum, const ADMOSController::ADMOSCParameter& param);
333
334 const juce::OSCMessage getParameterAsOSCMessage(int objNum, const ADMOSController::ADMOSCParameter& param);
335
336private:
337 //==============================================================================
338 const juce::String s_admObjDomainStr = "/adm/obj/";
339 const juce::String s_xStr= "/x";
340 const juce::String s_yStr= "/y";
341 const juce::String s_zStr= "/z";
342 const juce::String s_xyStr= "/xy";
343 const juce::String s_xyzStr= "/xyz";
344 const juce::String s_widthStr = "/w";
345 const juce::String s_muteStr= "/mute";
346
347 //==============================================================================
348 std::unique_ptr<juce::OSCReceiver> m_oscReceiver;
349 std::unique_ptr<juce::OSCSender> m_oscSender;
350
351 //==============================================================================
352 std::vector<int> m_knownObjNums;
353 std::mutex m_objCacheMutex;
354 std::map<int, std::map<std::uint16_t, ADMOSCParameter>> m_objCache;
355
356 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ADMOSController)
357};
358
359}
ADMOSCParameterChangeTarget getTarget() const
ADMOSCParameterChangedMessage(int objNum, std::uint16_t type, ADMOSCParameterChangeTarget target)
static bool createAndPostIfNotAlreadyPending(int objNum, std::uint16_t type, ADMOSCParameterChangeTarget target, ADMOSController *postTarget)
Receives ADM-OSC UDP packets and translates them into panning position and mute updates.
ADMOSCParameter getParameter(int objNum, std::uint16_t type)
bool startConnection(int oscPort, juce::IPAddress targetIP, int targetPort)
void handleMessage(const Message &message) override
void oscBundleReceived(const juce::OSCBundle &bundle) override
const std::vector< int > getObjNumsFromObjIdent(const juce::String &objIdent)
void setNumObjects(int numObjects)
bool sendParameterChange(int objNum, const ADMOSController::ADMOSCParameter &param)
void setParameter(int objNum, const ADMOSCParameter &param, const ADMOSCParameterChangeTarget &pct=ADMOSCParameterChangeTarget::None)
std::function< void(int, std::uint16_t)> onParameterChanged
void oscMessageReceived(const juce::OSCMessage &message) override
const juce::OSCMessage getParameterAsOSCMessage(int objNum, const ADMOSController::ADMOSCParameter &param)
Definition Mema.cpp:27
ADMOSCParameterMute(const ADMOSCParameter &other)
ADMOSCParameterWidth(const ADMOSCParameter &other)
ADMOSCParameterXYZ(float xVal, float yVal, float zVal)
std::tuple< float, float, float > getParameterVals()
ADMOSCParameterXYZ(const ADMOSCParameter &other)
ADMOSCParameterXY(const ADMOSCParameter &other)
std::tuple< float, float > getParameterVals()
ADMOSCParameterX(const ADMOSCParameter &other)
ADMOSCParameterY(const ADMOSCParameter &other)
ADMOSCParameterZ(const ADMOSCParameter &other)