1 /*
2  * Carla Plugin Host
3  * Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
16  */
17 
18 #include "CarlaEngineOsc.hpp"
19 
20 #ifdef HAVE_LIBLO
21 
22 #include "CarlaBackendUtils.hpp"
23 #include "CarlaEngine.hpp"
24 #include "CarlaPlugin.hpp"
25 
26 CARLA_BACKEND_START_NAMESPACE
27 
28 static const char* const kNullString = "";
29 
30 // -----------------------------------------------------------------------
31 
sendCallback(const EngineCallbackOpcode action,const uint pluginId,const int value1,const int value2,const int value3,const float valuef,const char * const valueStr) const32 void CarlaEngineOsc::sendCallback(const EngineCallbackOpcode action, const uint pluginId,
33                                   const int value1, const int value2, const int value3,
34                                   const float valuef, const char* const valueStr) const noexcept
35 {
36     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
37     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
38     carla_stdout("CarlaEngineOsc::sendCallback(%i:%s, %i, %i, %i, %i, %f, \"%s\")",
39                 action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3,
40                  static_cast<double>(valuef), valueStr);
41 
42     char targetPath[std::strlen(fControlDataTCP.path)+4];
43     std::strcpy(targetPath, fControlDataTCP.path);
44     std::strcat(targetPath, "/cb");
45     try_lo_send(fControlDataTCP.target, targetPath, "iiiiifs",
46                 action, pluginId, value1, value2, value3, static_cast<double>(valuef),
47                 valueStr != nullptr ? valueStr : kNullString);
48 }
49 
sendPluginInfo(const CarlaPluginPtr & plugin) const50 void CarlaEngineOsc::sendPluginInfo(const CarlaPluginPtr& plugin) const noexcept
51 {
52     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
53     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
54     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
55     carla_stdout("CarlaEngineOsc::sendPluginInfo(%p)", plugin.get());
56 
57     char bufRealName[STR_MAX+1], bufLabel[STR_MAX+1], bufMaker[STR_MAX+1], bufCopyright[STR_MAX+1];
58     carla_zeroChars(bufRealName, STR_MAX+1);
59     carla_zeroChars(bufLabel, STR_MAX+1);
60     carla_zeroChars(bufMaker, STR_MAX+1);
61     carla_zeroChars(bufCopyright, STR_MAX+1);
62 
63     if (! plugin->getRealName(bufRealName))
64         bufRealName[0] = '\0';
65     if (! plugin->getLabel(bufLabel))
66         bufLabel[0] = '\0';
67     if (! plugin->getMaker(bufMaker))
68         bufMaker[0] = '\0';
69     if (! plugin->getCopyright(bufCopyright))
70         bufCopyright[0] = '\0';
71 
72     const char* name = plugin->getName();
73     const char* filename = plugin->getFilename();
74     const char* iconName = plugin->getIconName();
75 
76     if (name == nullptr)
77         name = kNullString;
78     if (filename == nullptr)
79         filename = kNullString;
80     if (iconName == nullptr)
81         iconName = kNullString;
82 
83     char targetPath[std::strlen(fControlDataTCP.path)+6];
84     std::strcpy(targetPath, fControlDataTCP.path);
85     std::strcat(targetPath, "/info");
86     try_lo_send(fControlDataTCP.target, targetPath, "iiiihiisssssss",
87                 static_cast<int32_t>(plugin->getId()),
88                 static_cast<int32_t>(plugin->getType()),
89                 static_cast<int32_t>(plugin->getCategory()),
90                 static_cast<int32_t>(plugin->getHints()),
91                 static_cast<int64_t>(plugin->getUniqueId()),
92                 static_cast<int64_t>(plugin->getOptionsAvailable()),
93                 static_cast<int64_t>(plugin->getOptionsEnabled()),
94                 name, filename, iconName,
95                 bufRealName, bufLabel, bufMaker, bufCopyright);
96 }
97 
sendPluginPortCount(const CarlaPluginPtr & plugin) const98 void CarlaEngineOsc::sendPluginPortCount(const CarlaPluginPtr& plugin) const noexcept
99 {
100     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
101     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
102     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
103     carla_stdout("CarlaEngineOsc::sendPluginPortCount(%p)", plugin.get());
104 
105     uint32_t paramIns, paramOuts;
106     plugin->getParameterCountInfo(paramIns, paramOuts);
107 
108     if (paramIns > 49)
109         paramIns = 49;
110     if (paramOuts > 49)
111         paramOuts = 49;
112 
113     char targetPath[std::strlen(fControlDataTCP.path)+7];
114     std::strcpy(targetPath, fControlDataTCP.path);
115     std::strcat(targetPath, "/ports");
116     try_lo_send(fControlDataTCP.target, targetPath, "iiiiiiii",
117                 static_cast<int32_t>(plugin->getId()),
118                 static_cast<int32_t>(plugin->getAudioInCount()),
119                 static_cast<int32_t>(plugin->getAudioOutCount()),
120                 static_cast<int32_t>(plugin->getMidiInCount()),
121                 static_cast<int32_t>(plugin->getMidiOutCount()),
122                 static_cast<int32_t>(paramIns),
123                 static_cast<int32_t>(paramOuts),
124                 static_cast<int32_t>(plugin->getParameterCount()));
125 }
126 
sendPluginParameterInfo(const CarlaPluginPtr & plugin,const uint32_t index) const127 void CarlaEngineOsc::sendPluginParameterInfo(const CarlaPluginPtr& plugin, const uint32_t index) const noexcept
128 {
129     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
130     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
131     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
132     carla_debug("CarlaEngineOsc::sendPluginParameterInfo(%p, %u)", plugin.get(), index);
133 
134     char bufName[STR_MAX+1], bufUnit[STR_MAX+1], bufComment[STR_MAX+1], bufGroupName[STR_MAX+1];
135     carla_zeroChars(bufName, STR_MAX+1);
136     carla_zeroChars(bufUnit, STR_MAX+1);
137     carla_zeroChars(bufComment, STR_MAX+1);
138     carla_zeroChars(bufGroupName, STR_MAX+1);
139 
140     if (! plugin->getParameterName(index, bufName))
141         bufName[0] = '\0';
142     if (! plugin->getParameterUnit(index, bufUnit))
143         bufUnit[0] = '\0';
144     if (! plugin->getParameterComment(index, bufComment))
145         bufComment[0] = '\0';
146     if (! plugin->getParameterGroupName(index, bufGroupName))
147         bufGroupName[0] = '\0';
148 
149     const ParameterData& paramData(plugin->getParameterData(index));
150     const ParameterRanges& paramRanges(plugin->getParameterRanges(index));
151 
152     const int32_t pluginId = static_cast<int32_t>(plugin->getId());
153     const int32_t paramId  = static_cast<int32_t>(index);
154 
155     char targetPath[std::strlen(fControlDataTCP.path)+13];
156 
157     std::strcpy(targetPath, fControlDataTCP.path);
158     std::strcat(targetPath, "/paramInfo");
159     try_lo_send(fControlDataTCP.target, targetPath, "iissss",
160                 pluginId,
161                 paramId,
162                 bufName,
163                 bufUnit,
164                 bufComment,
165                 bufGroupName);
166 
167     std::strcpy(targetPath, fControlDataTCP.path);
168     std::strcat(targetPath, "/paramData");
169     try_lo_send(fControlDataTCP.target, targetPath, "iiiiiifff",
170                 pluginId,
171                 paramId,
172                 static_cast<int32_t>(paramData.type),
173                 static_cast<int32_t>(paramData.hints),
174                 static_cast<int32_t>(paramData.midiChannel),
175                 static_cast<int32_t>(paramData.mappedControlIndex),
176                 static_cast<double>(paramData.mappedMinimum),
177                 static_cast<double>(paramData.mappedMaximum),
178                 static_cast<double>(plugin->getParameterValue(index)));
179 
180     std::strcpy(targetPath, fControlDataTCP.path);
181     std::strcat(targetPath, "/paramRanges");
182     try_lo_send(fControlDataTCP.target, targetPath, "iiffffff",
183                 pluginId,
184                 paramId,
185                 static_cast<double>(paramRanges.def),
186                 static_cast<double>(paramRanges.min),
187                 static_cast<double>(paramRanges.max),
188                 static_cast<double>(paramRanges.step),
189                 static_cast<double>(paramRanges.stepSmall),
190                 static_cast<double>(paramRanges.stepLarge));
191 }
192 
sendPluginDataCount(const CarlaPluginPtr & plugin) const193 void CarlaEngineOsc::sendPluginDataCount(const CarlaPluginPtr& plugin) const noexcept
194 {
195     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
196     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
197     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
198     carla_stdout("CarlaEngineOsc::sendPluginDataCount(%p)", plugin.get());
199 
200     char targetPath[std::strlen(fControlDataTCP.path)+7];
201     std::strcpy(targetPath, fControlDataTCP.path);
202     std::strcat(targetPath, "/count");
203     try_lo_send(fControlDataTCP.target, targetPath, "iiiiii",
204                 static_cast<int32_t>(plugin->getId()),
205                 static_cast<int32_t>(plugin->getProgramCount()),
206                 static_cast<int32_t>(plugin->getMidiProgramCount()),
207                 static_cast<int32_t>(plugin->getCustomDataCount()),
208                 static_cast<int32_t>(plugin->getCurrentProgram()),
209                 static_cast<int32_t>(plugin->getCurrentMidiProgram()));
210 }
211 
sendPluginProgramCount(const CarlaPluginPtr & plugin) const212 void CarlaEngineOsc::sendPluginProgramCount(const CarlaPluginPtr& plugin) const noexcept
213 {
214     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
215     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
216     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
217     carla_stdout("CarlaEngineOsc::sendPluginDataCount(%p)", plugin.get());
218 
219     char targetPath[std::strlen(fControlDataTCP.path)+7];
220     std::strcpy(targetPath, fControlDataTCP.path);
221     std::strcat(targetPath, "/pcount");
222     try_lo_send(fControlDataTCP.target, targetPath, "iii",
223                 static_cast<int32_t>(plugin->getId()),
224                 static_cast<int32_t>(plugin->getProgramCount()),
225                 static_cast<int32_t>(plugin->getMidiProgramCount()));
226 }
227 
sendPluginProgram(const CarlaPluginPtr & plugin,const uint32_t index) const228 void CarlaEngineOsc::sendPluginProgram(const CarlaPluginPtr& plugin, const uint32_t index) const noexcept
229 {
230     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
231     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
232     carla_stdout("CarlaEngineOsc::sendPluginProgram(%p, %u)", plugin.get(), index);
233 
234     char strBuf[STR_MAX+1];
235     carla_zeroChars(strBuf, STR_MAX+1);
236     if (! plugin->getProgramName(index, strBuf))
237         strBuf[0] = '\0';
238 
239     char targetPath[std::strlen(fControlDataTCP.path)+6];
240     std::strcpy(targetPath, fControlDataTCP.path);
241     std::strcat(targetPath, "/prog");
242     try_lo_send(fControlDataTCP.target, targetPath, "iis",
243                 static_cast<int32_t>(plugin->getId()), static_cast<int32_t>(index), strBuf);
244 }
245 
sendPluginMidiProgram(const CarlaPluginPtr & plugin,const uint32_t index) const246 void CarlaEngineOsc::sendPluginMidiProgram(const CarlaPluginPtr& plugin, const uint32_t index) const noexcept
247 {
248     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
249     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
250     carla_stdout("CarlaEngineOsc::sendPluginProgram(%p, %u)", plugin.get(), index);
251 
252     const MidiProgramData& mpdata(plugin->getMidiProgramData(index));
253     CARLA_SAFE_ASSERT_RETURN(mpdata.name != nullptr,);
254 
255     char targetPath[std::strlen(fControlDataTCP.path)+7];
256     std::strcpy(targetPath, fControlDataTCP.path);
257     std::strcat(targetPath, "/mprog");
258     try_lo_send(fControlDataTCP.target, targetPath, "iiiis",
259                 static_cast<int32_t>(plugin->getId()),
260                 static_cast<int32_t>(index),
261                 static_cast<int32_t>(mpdata.bank), static_cast<int32_t>(mpdata.program), mpdata.name);
262 }
263 
sendPluginCustomData(const CarlaPluginPtr & plugin,const uint32_t index) const264 void CarlaEngineOsc::sendPluginCustomData(const CarlaPluginPtr& plugin, const uint32_t index) const noexcept
265 {
266     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
267     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
268     carla_stdout("CarlaEngineOsc::sendPluginCustomData(%p, %u)", plugin.get(), index);
269 
270     const CustomData& cdata(plugin->getCustomData(index));
271     CARLA_SAFE_ASSERT_RETURN(cdata.isValid(),);
272 
273     char targetPath[std::strlen(fControlDataTCP.path)+7];
274     std::strcpy(targetPath, fControlDataTCP.path);
275     std::strcat(targetPath, "/cdata");
276     try_lo_send(fControlDataTCP.target, targetPath, "iisss",
277                 static_cast<int32_t>(plugin->getId()),
278                 static_cast<int32_t>(index),
279                 cdata.type, cdata.key, cdata.value);
280 }
281 
sendPluginInternalParameterValues(const CarlaPluginPtr & plugin) const282 void CarlaEngineOsc::sendPluginInternalParameterValues(const CarlaPluginPtr& plugin) const noexcept
283 {
284     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
285     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
286     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
287     carla_debug("CarlaEngineOsc::sendPluginInternalParameterValues(%p)", plugin.get());
288 
289 #ifdef CARLA_PROPER_CPP11_SUPPORT
290     static_assert(PARAMETER_ACTIVE == -2 && PARAMETER_MAX == -9, "Incorrect data");
291 #endif
292 
293     double iparams[7];
294 
295     for (int32_t i = 0; i < 7; ++i)
296         iparams[i] = plugin->getInternalParameterValue(PARAMETER_ACTIVE - i);
297 
298     char targetPath[std::strlen(fControlDataTCP.path)+9];
299     std::strcpy(targetPath, fControlDataTCP.path);
300     std::strcat(targetPath, "/iparams");
301     try_lo_send(fControlDataTCP.target, targetPath, "ifffffff",
302                 static_cast<int32_t>(plugin->getId()),
303                 iparams[0], // PARAMETER_ACTIVE
304                 iparams[1], // PARAMETER_DRYWET
305                 iparams[2], // PARAMETER_VOLUME
306                 iparams[3], // PARAMETER_BALANCE_LEFT
307                 iparams[4], // PARAMETER_BALANCE_RIGHT
308                 iparams[5], // PARAMETER_PANNING
309                 iparams[6]  // PARAMETER_CTRL_CHANNEL
310                );
311 }
312 
313 // -----------------------------------------------------------------------
314 
sendPing() const315 void CarlaEngineOsc::sendPing() const noexcept
316 {
317     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
318     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
319 
320     char targetPath[std::strlen(fControlDataTCP.path)+6];
321     std::strcpy(targetPath, fControlDataTCP.path);
322     std::strcat(targetPath, "/ping");
323     try_lo_send(fControlDataTCP.target, targetPath, "");
324 }
325 
sendResponse(const int messageId,const char * const error) const326 void CarlaEngineOsc::sendResponse(const int messageId, const char* const error) const noexcept
327 {
328     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
329     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
330     carla_debug("CarlaEngineOsc::sendResponse()");
331 
332     char targetPath[std::strlen(fControlDataTCP.path)+6];
333     std::strcpy(targetPath, fControlDataTCP.path);
334     std::strcat(targetPath, "/resp");
335     try_lo_send(fControlDataTCP.target, targetPath, "is", messageId, error);
336 }
337 
sendExit() const338 void CarlaEngineOsc::sendExit() const noexcept
339 {
340     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.path != nullptr && fControlDataTCP.path[0] != '\0',);
341     CARLA_SAFE_ASSERT_RETURN(fControlDataTCP.target != nullptr,);
342     carla_debug("CarlaEngineOsc::sendExit()");
343 
344     char targetPath[std::strlen(fControlDataTCP.path)+6];
345     std::strcpy(targetPath, fControlDataTCP.path);
346     std::strcat(targetPath, "/exit");
347     try_lo_send(fControlDataTCP.target, targetPath, "");
348 }
349 
350 // -----------------------------------------------------------------------
351 
sendRuntimeInfo() const352 void CarlaEngineOsc::sendRuntimeInfo() const noexcept
353 {
354     CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.path != nullptr && fControlDataUDP.path[0] != '\0',);
355     CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.target != nullptr,);
356 
357     const EngineTimeInfo timeInfo(fEngine->getTimeInfo());
358 
359     char targetPath[std::strlen(fControlDataUDP.path)+9];
360     std::strcpy(targetPath, fControlDataUDP.path);
361     std::strcat(targetPath, "/runtime");
362     try_lo_send(fControlDataUDP.target, targetPath, "fiihiiif",
363                 static_cast<double>(fEngine->getDSPLoad()),
364                 static_cast<int32_t>(fEngine->getTotalXruns()),
365                 timeInfo.playing ? 1 : 0,
366                 static_cast<int64_t>(timeInfo.frame),
367                 static_cast<int32_t>(timeInfo.bbt.bar),
368                 static_cast<int32_t>(timeInfo.bbt.beat),
369                 static_cast<int32_t>(timeInfo.bbt.tick),
370                 timeInfo.bbt.beatsPerMinute);
371 }
372 
sendParameterValue(const uint pluginId,const uint32_t index,const float value) const373 void CarlaEngineOsc::sendParameterValue(const uint pluginId, const uint32_t index, const float value) const noexcept
374 {
375     CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.path != nullptr && fControlDataUDP.path[0] != '\0',);
376     CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.target != nullptr,);
377 
378     char targetPath[std::strlen(fControlDataUDP.path)+7];
379     std::strcpy(targetPath, fControlDataUDP.path);
380     std::strcat(targetPath, "/param");
381     try_lo_send(fControlDataUDP.target, targetPath, "iif",
382                 static_cast<int32_t>(pluginId),
383                 index,
384                 static_cast<double>(value));
385 }
386 
sendPeaks(const uint pluginId,const float peaks[4]) const387 void CarlaEngineOsc::sendPeaks(const uint pluginId, const float peaks[4]) const noexcept
388 {
389     CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.path != nullptr && fControlDataUDP.path[0] != '\0',);
390     CARLA_SAFE_ASSERT_RETURN(fControlDataUDP.target != nullptr,);
391 
392     char targetPath[std::strlen(fControlDataUDP.path)+7];
393     std::strcpy(targetPath, fControlDataUDP.path);
394     std::strcat(targetPath, "/peaks");
395     try_lo_send(fControlDataUDP.target, targetPath, "iffff", static_cast<int32_t>(pluginId),
396                 static_cast<double>(peaks[0]),
397                 static_cast<double>(peaks[1]),
398                 static_cast<double>(peaks[2]),
399                 static_cast<double>(peaks[3]));
400 }
401 
402 // -----------------------------------------------------------------------
403 
404 CARLA_BACKEND_END_NAMESPACE
405 
406 #endif // HAVE_LIBLO
407