1 /*
2  * Carla Standalone
3  * Copyright (C) 2011-2021 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 // TODO:
19 // Check carla_stderr2("Engine is not running"); <= prepend func name and args
20 
21 #include "CarlaHostImpl.hpp"
22 #include "CarlaMIDI.h"
23 
24 #include "CarlaEngineInit.hpp"
25 #include "CarlaPlugin.hpp"
26 
27 #include "CarlaBackendUtils.hpp"
28 #include "CarlaBase64Utils.hpp"
29 #include "ThreadSafeFFTW.hpp"
30 #ifndef BUILD_BRIDGE
31 # include "CarlaLogThread.hpp"
32 #endif
33 
34 #include "water/files/File.h"
35 
36 #define CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(cond, msg, ret) \
37     if (! (cond)) {                                              \
38         carla_stderr2("%s: " msg, __FUNCTION__);                 \
39         if (handle->isStandalone)                                \
40             ((CarlaHostStandalone*)handle)->lastError = msg;     \
41         return ret;                                              \
42     }
43 
44 // --------------------------------------------------------------------------------------------------------------------
45 
46 #ifdef USING_JUCE
47 static void carla_standalone_juce_init(void);
48 static void carla_standalone_juce_idle(void);
49 static void carla_standalone_juce_cleanup(void);
50 # define carla_juce_init carla_standalone_juce_init
51 # define carla_juce_idle carla_standalone_juce_idle
52 # define carla_juce_cleanup carla_standalone_juce_cleanup
53 # include "utils/JUCE.cpp"
54 # undef carla_juce_init
55 # undef carla_juce_idle
56 # undef carla_juce_cleanup
57 #endif
58 
59 // -------------------------------------------------------------------------------------------------------------------
60 // Always return a valid string ptr for standalone functions
61 
62 static const char* const gNullCharPtr = "";
63 
checkStringPtr(const char * & charPtr)64 static void checkStringPtr(const char*& charPtr) noexcept
65 {
66     if (charPtr == nullptr)
67         charPtr = gNullCharPtr;
68 }
69 
70 // -------------------------------------------------------------------------------------------------------------------
71 // Constructors
72 
_CarlaPluginInfo()73 _CarlaPluginInfo::_CarlaPluginInfo() noexcept
74     : type(CB::PLUGIN_NONE),
75       category(CB::PLUGIN_CATEGORY_NONE),
76       hints(0x0),
77       optionsAvailable(0x0),
78       optionsEnabled(0x0),
79       filename(gNullCharPtr),
80       name(gNullCharPtr),
81       label(gNullCharPtr),
82       maker(gNullCharPtr),
83       copyright(gNullCharPtr),
84       iconName(gNullCharPtr),
85       uniqueId(0) {}
86 
~_CarlaPluginInfo()87 _CarlaPluginInfo::~_CarlaPluginInfo() noexcept
88 {
89     if (label != gNullCharPtr)
90         delete[] label;
91     if (maker != gNullCharPtr)
92         delete[] maker;
93     if (copyright != gNullCharPtr)
94         delete[] copyright;
95 }
96 
_CarlaParameterInfo()97 _CarlaParameterInfo::_CarlaParameterInfo() noexcept
98     : name(gNullCharPtr),
99       symbol(gNullCharPtr),
100       unit(gNullCharPtr),
101       comment(gNullCharPtr),
102       groupName(gNullCharPtr),
103       scalePointCount(0) {}
104 
~_CarlaParameterInfo()105 _CarlaParameterInfo::~_CarlaParameterInfo() noexcept
106 {
107     if (name != gNullCharPtr)
108         delete[] name;
109     if (symbol != gNullCharPtr)
110         delete[] symbol;
111     if (unit != gNullCharPtr)
112         delete[] unit;
113     if (comment != gNullCharPtr)
114         delete[] comment;
115     if (groupName != gNullCharPtr)
116         delete[] groupName;
117 }
118 
_CarlaScalePointInfo()119 _CarlaScalePointInfo::_CarlaScalePointInfo() noexcept
120     : value(0.0f),
121       label(gNullCharPtr) {}
122 
~_CarlaScalePointInfo()123 _CarlaScalePointInfo::~_CarlaScalePointInfo() noexcept
124 {
125     if (label != gNullCharPtr)
126         delete[] label;
127 }
128 
_CarlaTransportInfo()129 _CarlaTransportInfo::_CarlaTransportInfo() noexcept
130     : playing(false),
131       frame(0),
132       bar(0),
133       beat(0),
134       tick(0),
135       bpm(0.0) {}
136 
clear()137 void _CarlaTransportInfo::clear() noexcept
138 {
139     playing = false;
140     frame = 0;
141     bar = 0;
142     beat = 0;
143     tick = 0;
144     bpm = 0.0;
145 }
146 
147 // --------------------------------------------------------------------------------------------------------------------
148 
149 using CarlaBackend::CarlaPluginPtr;
150 
151 // --------------------------------------------------------------------------------------------------------------------
152 
carla_get_engine_driver_count()153 uint carla_get_engine_driver_count()
154 {
155     carla_debug("carla_get_engine_driver_count()");
156 
157     return CarlaEngine::getDriverCount();
158 }
159 
carla_get_engine_driver_name(uint index)160 const char* carla_get_engine_driver_name(uint index)
161 {
162     carla_debug("carla_get_engine_driver_name(%i)", index);
163 
164     return CarlaEngine::getDriverName(index);
165 }
166 
carla_get_engine_driver_device_names(uint index)167 const char* const* carla_get_engine_driver_device_names(uint index)
168 {
169     carla_debug("carla_get_engine_driver_device_names(%i)", index);
170 
171     return CarlaEngine::getDriverDeviceNames(index);
172 }
173 
carla_get_engine_driver_device_info(uint index,const char * name)174 const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(uint index, const char* name)
175 {
176     CARLA_SAFE_ASSERT_RETURN(name != nullptr, nullptr);
177 
178     static EngineDriverDeviceInfo retDevInfo;
179     static const uint32_t nullBufferSizes[] = { 0   };
180     static const double   nullSampleRates[] = { 0.0 };
181 
182     carla_debug("carla_get_engine_driver_device_info(%i, \"%s\")", index, name);
183 
184     if (const EngineDriverDeviceInfo* const devInfo = CarlaEngine::getDriverDeviceInfo(index, name))
185     {
186         retDevInfo.hints       =  devInfo->hints;
187         retDevInfo.bufferSizes = (devInfo->bufferSizes != nullptr) ? devInfo->bufferSizes : nullBufferSizes;
188         retDevInfo.sampleRates = (devInfo->sampleRates != nullptr) ? devInfo->sampleRates : nullSampleRates;
189     }
190     else
191     {
192         retDevInfo.hints       = 0x0;
193         retDevInfo.bufferSizes = nullBufferSizes;
194         retDevInfo.sampleRates = nullSampleRates;
195     }
196 
197     return &retDevInfo;
198 }
199 
carla_show_engine_driver_device_control_panel(uint index,const char * name)200 bool carla_show_engine_driver_device_control_panel(uint index, const char* name)
201 {
202     return CarlaEngine::showDriverDeviceControlPanel(index, name);
203 }
204 
205 // --------------------------------------------------------------------------------------------------------------------
206 
carla_standalone_host_init(void)207 CarlaHostHandle carla_standalone_host_init(void)
208 {
209 #ifdef CARLA_OS_UNIX
210     static const ThreadSafeFFTW sThreadSafeFFTW;
211 #endif
212 
213     static CarlaHostStandalone gStandalone;
214 
215     return &gStandalone;
216 }
217 
carla_get_engine_from_handle(CarlaHostHandle handle)218 CarlaEngine* carla_get_engine_from_handle(CarlaHostHandle handle)
219 {
220     carla_debug("carla_get_engine(%p)", handle);
221 
222     return handle->engine;
223 }
224 
225 // --------------------------------------------------------------------------------------------------------------------
226 
carla_engine_init_common(const CarlaHostStandalone & standalone,CarlaEngine * const engine)227 static void carla_engine_init_common(const CarlaHostStandalone& standalone, CarlaEngine* const engine)
228 {
229     engine->setCallback(standalone.engineCallback, standalone.engineCallbackPtr);
230     engine->setFileCallback(standalone.fileCallback, standalone.fileCallbackPtr);
231 
232     using water::File;
233     const File waterBinaryDir(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory());
234 
235 #ifdef BUILD_BRIDGE
236     /*
237     if (const char* const forceStereo = std::getenv("ENGINE_OPTION_FORCE_STEREO"))
238         engine->setOption(CB::ENGINE_OPTION_FORCE_STEREO, (std::strcmp(forceStereo, "true") == 0) ? 1 : 0, nullptr);
239 
240     if (const char* const preferPluginBridges = std::getenv("ENGINE_OPTION_PREFER_PLUGIN_BRIDGES"))
241         engine->setOption(CB::ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, (std::strcmp(preferPluginBridges, "true") == 0) ? 1 : 0, nullptr);
242 
243     if (const char* const preferUiBridges = std::getenv("ENGINE_OPTION_PREFER_UI_BRIDGES"))
244         engine->setOption(CB::ENGINE_OPTION_PREFER_UI_BRIDGES, (std::strcmp(preferUiBridges, "true") == 0) ? 1 : 0, nullptr);
245     */
246 
247     if (const char* const uisAlwaysOnTop = std::getenv("ENGINE_OPTION_UIS_ALWAYS_ON_TOP"))
248         engine->setOption(CB::ENGINE_OPTION_UIS_ALWAYS_ON_TOP, (std::strcmp(uisAlwaysOnTop, "true") == 0) ? 1 : 0, nullptr);
249 
250     if (const char* const maxParameters = std::getenv("ENGINE_OPTION_MAX_PARAMETERS"))
251         engine->setOption(CB::ENGINE_OPTION_MAX_PARAMETERS, std::atoi(maxParameters), nullptr);
252 
253     if (const char* const resetXruns = std::getenv("ENGINE_OPTION_RESET_XRUNS"))
254         engine->setOption(CB::ENGINE_OPTION_RESET_XRUNS, (std::strcmp(resetXruns, "true") == 0) ? 1 : 0, nullptr);
255 
256     if (const char* const uiBridgesTimeout = std::getenv("ENGINE_OPTION_UI_BRIDGES_TIMEOUT"))
257         engine->setOption(CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT, std::atoi(uiBridgesTimeout), nullptr);
258 
259     if (const char* const pathAudio = std::getenv("ENGINE_OPTION_FILE_PATH_AUDIO"))
260         engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_AUDIO, pathAudio);
261 
262     if (const char* const pathMIDI = std::getenv("ENGINE_OPTION_FILE_PATH_MIDI"))
263         engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_MIDI, pathMIDI);
264 
265     if (const char* const pathLADSPA = std::getenv("ENGINE_OPTION_PLUGIN_PATH_LADSPA"))
266         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_LADSPA, pathLADSPA);
267 
268     if (const char* const pathDSSI = std::getenv("ENGINE_OPTION_PLUGIN_PATH_DSSI"))
269         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_DSSI, pathDSSI);
270 
271     if (const char* const pathLV2 = std::getenv("ENGINE_OPTION_PLUGIN_PATH_LV2"))
272         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_LV2, pathLV2);
273 
274     if (const char* const pathVST2 = std::getenv("ENGINE_OPTION_PLUGIN_PATH_VST2"))
275         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_VST2, pathVST2);
276 
277     if (const char* const pathVST3 = std::getenv("ENGINE_OPTION_PLUGIN_PATH_VST3"))
278         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_VST3, pathVST3);
279 
280     if (const char* const pathSF2 = std::getenv("ENGINE_OPTION_PLUGIN_PATH_SF2"))
281         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_SF2, pathSF2);
282 
283     if (const char* const pathSFZ = std::getenv("ENGINE_OPTION_PLUGIN_PATH_SFZ"))
284         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH, CB::PLUGIN_SFZ, pathSFZ);
285 
286     if (const char* const binaryDir = std::getenv("ENGINE_OPTION_PATH_BINARIES"))
287         engine->setOption(CB::ENGINE_OPTION_PATH_BINARIES, 0, binaryDir);
288     else
289         engine->setOption(CB::ENGINE_OPTION_PATH_BINARIES, 0, waterBinaryDir.getFullPathName().toRawUTF8());
290 
291     if (const char* const resourceDir = std::getenv("ENGINE_OPTION_PATH_RESOURCES"))
292         engine->setOption(CB::ENGINE_OPTION_PATH_RESOURCES, 0, resourceDir);
293     else
294         engine->setOption(CB::ENGINE_OPTION_PATH_RESOURCES, 0, waterBinaryDir.getChildFile("resources").getFullPathName().toRawUTF8());
295 
296     if (const char* const preventBadBehaviour = std::getenv("ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR"))
297         engine->setOption(CB::ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR, (std::strcmp(preventBadBehaviour, "true") == 0) ? 1 : 0, nullptr);
298 
299     if (const char* const frontendWinId = std::getenv("ENGINE_OPTION_FRONTEND_WIN_ID"))
300         engine->setOption(CB::ENGINE_OPTION_FRONTEND_WIN_ID, 0, frontendWinId);
301 #else
302     engine->setOption(CB::ENGINE_OPTION_FORCE_STEREO,          standalone.engineOptions.forceStereo         ? 1 : 0,        nullptr);
303     engine->setOption(CB::ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, standalone.engineOptions.preferPluginBridges ? 1 : 0,        nullptr);
304     engine->setOption(CB::ENGINE_OPTION_PREFER_UI_BRIDGES,     standalone.engineOptions.preferUiBridges     ? 1 : 0,        nullptr);
305     engine->setOption(CB::ENGINE_OPTION_UIS_ALWAYS_ON_TOP,     standalone.engineOptions.uisAlwaysOnTop      ? 1 : 0,        nullptr);
306     engine->setOption(CB::ENGINE_OPTION_MAX_PARAMETERS,        static_cast<int>(standalone.engineOptions.maxParameters),    nullptr);
307     engine->setOption(CB::ENGINE_OPTION_RESET_XRUNS,           standalone.engineOptions.resetXruns          ? 1 : 0,        nullptr);
308     engine->setOption(CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT,    static_cast<int>(standalone.engineOptions.uiBridgesTimeout), nullptr);
309     engine->setOption(CB::ENGINE_OPTION_AUDIO_BUFFER_SIZE,     static_cast<int>(standalone.engineOptions.audioBufferSize),  nullptr);
310     engine->setOption(CB::ENGINE_OPTION_AUDIO_SAMPLE_RATE,     static_cast<int>(standalone.engineOptions.audioSampleRate),  nullptr);
311     engine->setOption(CB::ENGINE_OPTION_AUDIO_TRIPLE_BUFFER,   standalone.engineOptions.audioTripleBuffer   ? 1 : 0,        nullptr);
312 
313     if (standalone.engineOptions.audioDriver != nullptr)
314         engine->setOption(CB::ENGINE_OPTION_AUDIO_DRIVER,      0, standalone.engineOptions.audioDriver);
315 
316     if (standalone.engineOptions.audioDevice != nullptr)
317         engine->setOption(CB::ENGINE_OPTION_AUDIO_DEVICE,      0, standalone.engineOptions.audioDevice);
318 
319     engine->setOption(CB::ENGINE_OPTION_OSC_ENABLED,  standalone.engineOptions.oscEnabled, nullptr);
320     engine->setOption(CB::ENGINE_OPTION_OSC_PORT_TCP, standalone.engineOptions.oscPortTCP, nullptr);
321     engine->setOption(CB::ENGINE_OPTION_OSC_PORT_UDP, standalone.engineOptions.oscPortUDP, nullptr);
322 
323     if (standalone.engineOptions.pathAudio != nullptr)
324         engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_AUDIO, standalone.engineOptions.pathAudio);
325 
326     if (standalone.engineOptions.pathMIDI != nullptr)
327         engine->setOption(CB::ENGINE_OPTION_FILE_PATH, CB::FILE_MIDI, standalone.engineOptions.pathMIDI);
328 
329     if (standalone.engineOptions.pathLADSPA != nullptr)
330         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_LADSPA, standalone.engineOptions.pathLADSPA);
331 
332     if (standalone.engineOptions.pathDSSI != nullptr)
333         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_DSSI, standalone.engineOptions.pathDSSI);
334 
335     if (standalone.engineOptions.pathLV2 != nullptr)
336         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_LV2, standalone.engineOptions.pathLV2);
337 
338     if (standalone.engineOptions.pathVST2 != nullptr)
339         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_VST2, standalone.engineOptions.pathVST2);
340 
341     if (standalone.engineOptions.pathVST3 != nullptr)
342         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_VST3, standalone.engineOptions.pathVST3);
343 
344     if (standalone.engineOptions.pathSF2 != nullptr)
345         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_SF2, standalone.engineOptions.pathSF2);
346 
347     if (standalone.engineOptions.pathSFZ != nullptr)
348         engine->setOption(CB::ENGINE_OPTION_PLUGIN_PATH,       CB::PLUGIN_SFZ, standalone.engineOptions.pathSFZ);
349 
350     if (standalone.engineOptions.binaryDir != nullptr && standalone.engineOptions.binaryDir[0] != '\0')
351         engine->setOption(CB::ENGINE_OPTION_PATH_BINARIES, 0, standalone.engineOptions.binaryDir);
352     else
353         engine->setOption(CB::ENGINE_OPTION_PATH_BINARIES, 0, waterBinaryDir.getFullPathName().toRawUTF8());
354 
355     if (standalone.engineOptions.resourceDir != nullptr && standalone.engineOptions.resourceDir[0] != '\0')
356         engine->setOption(CB::ENGINE_OPTION_PATH_RESOURCES,    0, standalone.engineOptions.resourceDir);
357 
358     engine->setOption(CB::ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR,    standalone.engineOptions.preventBadBehaviour ? 1 : 0,  nullptr);
359 
360     engine->setOption(CB::ENGINE_OPTION_FRONTEND_BACKGROUND_COLOR, static_cast<int>(standalone.engineOptions.bgColor), nullptr);
361     engine->setOption(CB::ENGINE_OPTION_FRONTEND_FOREGROUND_COLOR, static_cast<int>(standalone.engineOptions.fgColor), nullptr);
362     engine->setOption(CB::ENGINE_OPTION_FRONTEND_UI_SCALE, static_cast<int>(standalone.engineOptions.uiScale * 1000.0f), nullptr);
363 
364     if (standalone.engineOptions.frontendWinId != 0)
365     {
366         char strBuf[STR_MAX+1];
367         strBuf[STR_MAX] = '\0';
368         std::snprintf(strBuf, STR_MAX, P_UINTPTR, standalone.engineOptions.frontendWinId);
369         engine->setOption(CB::ENGINE_OPTION_FRONTEND_WIN_ID, 0, strBuf);
370     }
371     else
372     {
373         engine->setOption(CB::ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0");
374     }
375 
376 # ifndef CARLA_OS_WIN
377     if (standalone.engineOptions.wine.executable != nullptr && standalone.engineOptions.wine.executable[0] != '\0')
378         engine->setOption(CB::ENGINE_OPTION_WINE_EXECUTABLE, 0, standalone.engineOptions.wine.executable);
379 
380     engine->setOption(CB::ENGINE_OPTION_WINE_AUTO_PREFIX, standalone.engineOptions.wine.autoPrefix ? 1 : 0, nullptr);
381 
382     if (standalone.engineOptions.wine.fallbackPrefix != nullptr && standalone.engineOptions.wine.fallbackPrefix[0] != '\0')
383         engine->setOption(CB::ENGINE_OPTION_WINE_FALLBACK_PREFIX, 0, standalone.engineOptions.wine.fallbackPrefix);
384 
385     engine->setOption(CB::ENGINE_OPTION_WINE_RT_PRIO_ENABLED, standalone.engineOptions.wine.rtPrio ? 1 : 0, nullptr);
386     engine->setOption(CB::ENGINE_OPTION_WINE_BASE_RT_PRIO, standalone.engineOptions.wine.baseRtPrio, nullptr);
387     engine->setOption(CB::ENGINE_OPTION_WINE_SERVER_RT_PRIO, standalone.engineOptions.wine.serverRtPrio, nullptr);
388 # endif
389 
390     engine->setOption(CB::ENGINE_OPTION_CLIENT_NAME_PREFIX, 0, standalone.engineOptions.clientNamePrefix);
391 
392     engine->setOption(CB::ENGINE_OPTION_PLUGINS_ARE_STANDALONE, standalone.engineOptions.pluginsAreStandalone, nullptr);
393 #endif // BUILD_BRIDGE
394 }
395 
carla_engine_init(CarlaHostHandle handle,const char * driverName,const char * clientName)396 bool carla_engine_init(CarlaHostHandle handle, const char* driverName, const char* clientName)
397 {
398     CARLA_SAFE_ASSERT_RETURN(driverName != nullptr && driverName[0] != '\0', false);
399     CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false);
400     carla_debug("carla_engine_init(%p, \"%s\", \"%s\")", handle, driverName, clientName);
401 
402     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->isStandalone, "Must be a standalone host handle", false);
403     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine == nullptr, "Engine is already initialized", false);
404 
405 #ifdef CARLA_OS_WIN
406     carla_setenv("WINEASIO_CLIENT_NAME", clientName);
407 #endif
408 
409 #ifdef USING_JUCE
410     carla_standalone_juce_init();
411 #endif
412 
413     CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
414 
415     CarlaEngine* const engine = CarlaEngine::newDriverByName(driverName);
416     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(engine != nullptr, "The selected audio driver is not available", false);
417 
418     shandle.engine = engine;
419 
420 #ifdef BUILD_BRIDGE
421     if (std::getenv("CARLA_BRIDGE_DUMMY") != nullptr)
422     {
423         // engine->setOption(CB::ENGINE_OPTION_PROCESS_MODE,      CB::ENGINE_PROCESS_MODE_PATCHBAY,         nullptr);
424         engine->setOption(CB::ENGINE_OPTION_PROCESS_MODE,      CB::ENGINE_PROCESS_MODE_CONTINUOUS_RACK,  nullptr);
425         engine->setOption(CB::ENGINE_OPTION_TRANSPORT_MODE,    CB::ENGINE_TRANSPORT_MODE_INTERNAL,       nullptr);
426 
427         engine->setOption(CB::ENGINE_OPTION_AUDIO_BUFFER_SIZE, 4096, nullptr);
428         engine->setOption(CB::ENGINE_OPTION_AUDIO_SAMPLE_RATE, 48000, nullptr);
429     }
430     else
431     {
432         engine->setOption(CB::ENGINE_OPTION_PROCESS_MODE,      CB::ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, nullptr);
433         engine->setOption(CB::ENGINE_OPTION_TRANSPORT_MODE,    CB::ENGINE_TRANSPORT_MODE_JACK,           nullptr);
434     }
435     engine->setOption(CB::ENGINE_OPTION_FORCE_STEREO,          false,                                    nullptr);
436     engine->setOption(CB::ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, false,                                    nullptr);
437     engine->setOption(CB::ENGINE_OPTION_PREFER_UI_BRIDGES,     false,                                    nullptr);
438 #else
439     engine->setOption(CB::ENGINE_OPTION_PROCESS_MODE,          static_cast<int>(shandle.engineOptions.processMode),   nullptr);
440     engine->setOption(CB::ENGINE_OPTION_TRANSPORT_MODE,        static_cast<int>(shandle.engineOptions.transportMode), shandle.engineOptions.transportExtra);
441 #endif
442 
443     carla_engine_init_common(shandle, engine);
444 
445     if (engine->init(clientName))
446     {
447 #ifndef BUILD_BRIDGE
448         if (shandle.logThreadEnabled && std::getenv("CARLA_LOGS_DISABLED") == nullptr)
449             shandle.logThread.init();
450 #endif
451         shandle.lastError = "No error";
452         return true;
453     }
454     else
455     {
456         shandle.lastError = engine->getLastError();
457         shandle.engine = nullptr;
458         delete engine;
459 #ifdef USING_JUCE
460         carla_standalone_juce_cleanup();
461 #endif
462         return false;
463     }
464 }
465 
466 #ifdef BUILD_BRIDGE
carla_engine_init_bridge(CarlaHostHandle handle,const char audioBaseName[6+1],const char rtClientBaseName[6+1],const char nonRtClientBaseName[6+1],const char nonRtServerBaseName[6+1],const char * const clientName)467 bool carla_engine_init_bridge(CarlaHostHandle handle,
468                               const char audioBaseName[6+1],
469                               const char rtClientBaseName[6+1],
470                               const char nonRtClientBaseName[6+1],
471                               const char nonRtServerBaseName[6+1],
472                               const char* const clientName)
473 {
474     CARLA_SAFE_ASSERT_RETURN(audioBaseName != nullptr && audioBaseName[0] != '\0', false);
475     CARLA_SAFE_ASSERT_RETURN(rtClientBaseName != nullptr && rtClientBaseName[0] != '\0', false);
476     CARLA_SAFE_ASSERT_RETURN(nonRtClientBaseName != nullptr && nonRtClientBaseName[0] != '\0', false);
477     CARLA_SAFE_ASSERT_RETURN(nonRtServerBaseName != nullptr && nonRtServerBaseName[0] != '\0', false);
478     CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false);
479     carla_debug("carla_engine_init_bridge(%p, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\")",
480                 handle, audioBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName, clientName);
481 
482     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->isStandalone, "Must be a standalone host handle", false);
483     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine == nullptr, "Engine is already initialized", false);
484 
485     CarlaScopedPointer<CarlaEngine> engine(CB::EngineInit::newBridge(audioBaseName,
486                                                                      rtClientBaseName,
487                                                                      nonRtClientBaseName,
488                                                                      nonRtServerBaseName));
489 
490     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(engine != nullptr, "The selected audio driver is not available", false);
491 
492     engine->setOption(CB::ENGINE_OPTION_PROCESS_MODE,   CB::ENGINE_PROCESS_MODE_BRIDGE,   nullptr);
493     engine->setOption(CB::ENGINE_OPTION_TRANSPORT_MODE, CB::ENGINE_TRANSPORT_MODE_BRIDGE, nullptr);
494 
495     CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
496 
497     carla_engine_init_common(shandle, engine);
498 
499     if (engine->init(clientName))
500     {
501         shandle.lastError = "No error";
502         shandle.engine = engine.release();
503         return true;
504     }
505     else
506     {
507         shandle.lastError = engine->getLastError();
508         return false;
509     }
510 }
511 #endif
512 
carla_engine_close(CarlaHostHandle handle)513 bool carla_engine_close(CarlaHostHandle handle)
514 {
515     carla_debug("carla_engine_close(%p)", handle);
516 
517     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->isStandalone, "Must be a standalone host handle", false);
518     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
519 
520     CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
521 
522     CarlaEngine* const engine = shandle.engine;
523 
524     engine->setAboutToClose();
525     engine->removeAllPlugins();
526 
527     const bool closed = engine->close();
528 
529     if (! closed)
530         shandle.lastError = engine->getLastError();
531 
532 #ifndef BUILD_BRIDGE
533     shandle.logThread.stop();
534 #endif
535 
536     shandle.engine = nullptr;
537     delete engine;
538 
539 #ifdef USING_JUCE
540     carla_standalone_juce_cleanup();
541 #endif
542     return closed;
543 }
544 
carla_engine_idle(CarlaHostHandle handle)545 void carla_engine_idle(CarlaHostHandle handle)
546 {
547     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->isStandalone,);
548 
549     handle->engine->idle();
550 
551 #ifdef USING_JUCE
552     if (handle->isStandalone)
553         carla_standalone_juce_idle();
554 #endif
555 }
556 
carla_is_engine_running(CarlaHostHandle handle)557 bool carla_is_engine_running(CarlaHostHandle handle)
558 {
559     return (handle->engine != nullptr && handle->engine->isRunning());
560 }
561 
carla_get_runtime_engine_info(CarlaHostHandle handle)562 const CarlaRuntimeEngineInfo* carla_get_runtime_engine_info(CarlaHostHandle handle)
563 {
564     static CarlaRuntimeEngineInfo retInfo;
565 
566     // reset
567     retInfo.load = 0.0f;
568     retInfo.xruns = 0;
569 
570     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
571 
572     retInfo.load = handle->engine->getDSPLoad();
573     retInfo.xruns = handle->engine->getTotalXruns();
574 
575     return &retInfo;
576 }
577 
578 #ifndef BUILD_BRIDGE
carla_get_runtime_engine_driver_device_info(CarlaHostHandle handle)579 const CarlaRuntimeEngineDriverDeviceInfo* carla_get_runtime_engine_driver_device_info(CarlaHostHandle handle)
580 {
581     static CarlaRuntimeEngineDriverDeviceInfo retInfo;
582 
583     // reset
584     retInfo.name = gNullCharPtr;
585     retInfo.hints = 0x0;
586     retInfo.bufferSize = 0;
587     retInfo.bufferSizes = nullptr;
588     retInfo.sampleRate = 0.0;
589     retInfo.sampleRates = nullptr;
590 
591     const char* audioDriver;
592     const char* audioDevice;
593 
594     if (CarlaEngine* const engine = handle->engine)
595     {
596         audioDriver = engine->getCurrentDriverName();
597         audioDevice = engine->getOptions().audioDevice;
598 
599         retInfo.bufferSize = engine->getBufferSize();
600         retInfo.sampleRate = engine->getSampleRate();
601     }
602     else if (handle->isStandalone)
603     {
604         CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
605 
606         audioDriver = shandle.engineOptions.audioDriver;
607         audioDevice = shandle.engineOptions.audioDevice;
608 
609         retInfo.bufferSize = shandle.engineOptions.audioBufferSize;
610         retInfo.sampleRate = shandle.engineOptions.audioSampleRate;
611     }
612     else
613     {
614         return &retInfo;
615     }
616     CARLA_SAFE_ASSERT_RETURN(audioDriver != nullptr, &retInfo);
617     CARLA_SAFE_ASSERT_RETURN(audioDevice != nullptr, &retInfo);
618 
619     uint index = 0;
620     uint count = CarlaEngine::getDriverCount();
621     for (; index<count; ++index)
622     {
623         const char* const testDriverName = CarlaEngine::getDriverName(index);
624         CARLA_SAFE_ASSERT_CONTINUE(testDriverName != nullptr);
625 
626         if (std::strcmp(testDriverName, audioDriver) == 0)
627             break;
628     }
629     CARLA_SAFE_ASSERT_RETURN(index != count, &retInfo);
630 
631     const EngineDriverDeviceInfo* const devInfo = CarlaEngine::getDriverDeviceInfo(index, audioDevice);
632     CARLA_SAFE_ASSERT_RETURN(devInfo != nullptr, &retInfo);
633 
634     retInfo.name        = audioDevice;
635     retInfo.hints       = devInfo->hints;
636     retInfo.bufferSizes = devInfo->bufferSizes;
637     retInfo.sampleRates = devInfo->sampleRates;
638 
639     return &retInfo;
640 }
641 
carla_set_engine_buffer_size_and_sample_rate(CarlaHostHandle handle,uint bufferSize,double sampleRate)642 bool carla_set_engine_buffer_size_and_sample_rate(CarlaHostHandle handle, uint bufferSize, double sampleRate)
643 {
644     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, false);
645     carla_debug("carla_set_engine_buffer_size_and_sample_rate(%p, %u, %f)", handle, bufferSize, sampleRate);
646 
647     return handle->engine->setBufferSizeAndSampleRate(bufferSize, sampleRate);
648 }
649 
carla_show_engine_device_control_panel(CarlaHostHandle handle)650 bool carla_show_engine_device_control_panel(CarlaHostHandle handle)
651 {
652     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, false);
653     carla_debug("carla_show_engine_device_control_panel(%p)", handle);
654 
655     return handle->engine->showDeviceControlPanel();
656 }
657 #endif // BUILD_BRIDGE
658 
carla_clear_engine_xruns(CarlaHostHandle handle)659 void carla_clear_engine_xruns(CarlaHostHandle handle)
660 {
661     if (handle->engine != nullptr)
662         handle->engine->clearXruns();
663 }
664 
carla_cancel_engine_action(CarlaHostHandle handle)665 void carla_cancel_engine_action(CarlaHostHandle handle)
666 {
667     if (handle->engine != nullptr)
668         handle->engine->setActionCanceled(true);
669 }
670 
carla_set_engine_about_to_close(CarlaHostHandle handle)671 bool carla_set_engine_about_to_close(CarlaHostHandle handle)
672 {
673     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, true);
674     carla_debug("carla_set_engine_about_to_close(%p)", handle);
675 
676     return handle->engine->setAboutToClose();
677 }
678 
carla_set_engine_callback(CarlaHostHandle handle,EngineCallbackFunc func,void * ptr)679 void carla_set_engine_callback(CarlaHostHandle handle, EngineCallbackFunc func, void* ptr)
680 {
681     carla_debug("carla_set_engine_callback(%p, %p, %p)", handle, func, ptr);
682 
683     if (handle->isStandalone)
684     {
685         CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
686 
687         shandle.engineCallback    = func;
688         shandle.engineCallbackPtr = ptr;
689 
690 #ifndef BUILD_BRIDGE
691         shandle.logThread.setCallback(func, ptr);
692 #endif
693     }
694 
695     if (handle->engine != nullptr)
696         handle->engine->setCallback(func, ptr);
697 }
698 
carla_set_engine_option(CarlaHostHandle handle,EngineOption option,int value,const char * valueStr)699 void carla_set_engine_option(CarlaHostHandle handle, EngineOption option, int value, const char* valueStr)
700 {
701     carla_debug("carla_set_engine_option(%p, %i:%s, %i, \"%s\")",
702                 handle, option, CB::EngineOption2Str(option), value, valueStr);
703 
704     if (handle->isStandalone)
705     {
706         CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
707 
708         switch (option)
709         {
710         case CB::ENGINE_OPTION_DEBUG:
711             break;
712 
713         case CB::ENGINE_OPTION_PROCESS_MODE:
714             CARLA_SAFE_ASSERT_RETURN(value >= CB::ENGINE_PROCESS_MODE_SINGLE_CLIENT && value < CB::ENGINE_PROCESS_MODE_BRIDGE,);
715             shandle.engineOptions.processMode = static_cast<CB::EngineProcessMode>(value);
716             break;
717 
718         case CB::ENGINE_OPTION_TRANSPORT_MODE:
719             CARLA_SAFE_ASSERT_RETURN(value >= CB::ENGINE_TRANSPORT_MODE_DISABLED && value <= CB::ENGINE_TRANSPORT_MODE_BRIDGE,);
720 
721             // jack transport cannot be disabled in multi-client
722             if (shandle.engineOptions.processMode == CB::ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
723                 && value != CB::ENGINE_TRANSPORT_MODE_JACK)
724             {
725                 shandle.engineOptions.transportMode = CB::ENGINE_TRANSPORT_MODE_JACK;
726 
727                 if (shandle.engineCallback != nullptr)
728                     shandle.engineCallback(shandle.engineCallbackPtr,
729                                            CB::ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED,
730                                            0,
731                                            CB::ENGINE_TRANSPORT_MODE_JACK,
732                                            0, 0, 0.0f,
733                                            shandle.engineOptions.transportExtra);
734             }
735             else
736             {
737                 shandle.engineOptions.transportMode = static_cast<CB::EngineTransportMode>(value);
738             }
739 
740             delete[] shandle.engineOptions.transportExtra;
741             if (value != CB::ENGINE_TRANSPORT_MODE_DISABLED && valueStr != nullptr)
742                 shandle.engineOptions.transportExtra = carla_strdup_safe(valueStr);
743             else
744                 shandle.engineOptions.transportExtra = nullptr;
745             break;
746 
747         case CB::ENGINE_OPTION_FORCE_STEREO:
748             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
749             shandle.engineOptions.forceStereo = (value != 0);
750             break;
751 
752         case CB::ENGINE_OPTION_PREFER_PLUGIN_BRIDGES:
753             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
754             shandle.engineOptions.preferPluginBridges = (value != 0);
755             break;
756 
757         case CB::ENGINE_OPTION_PREFER_UI_BRIDGES:
758             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
759             shandle.engineOptions.preferUiBridges = (value != 0);
760             break;
761 
762         case CB::ENGINE_OPTION_UIS_ALWAYS_ON_TOP:
763             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
764             shandle.engineOptions.uisAlwaysOnTop = (value != 0);
765             break;
766 
767         case CB::ENGINE_OPTION_MAX_PARAMETERS:
768             CARLA_SAFE_ASSERT_RETURN(value >= 0,);
769             shandle.engineOptions.maxParameters = static_cast<uint>(value);
770             break;
771 
772         case CB::ENGINE_OPTION_RESET_XRUNS:
773             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
774             shandle.engineOptions.resetXruns = (value != 0);
775             break;
776 
777         case CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT:
778             CARLA_SAFE_ASSERT_RETURN(value >= 0,);
779             shandle.engineOptions.uiBridgesTimeout = static_cast<uint>(value);
780             break;
781 
782         case CB::ENGINE_OPTION_AUDIO_BUFFER_SIZE:
783             CARLA_SAFE_ASSERT_RETURN(value >= 8,);
784             shandle.engineOptions.audioBufferSize = static_cast<uint>(value);
785             break;
786 
787         case CB::ENGINE_OPTION_AUDIO_SAMPLE_RATE:
788             CARLA_SAFE_ASSERT_RETURN(value >= 22050,);
789             shandle.engineOptions.audioSampleRate = static_cast<uint>(value);
790             break;
791 
792         case CB::ENGINE_OPTION_AUDIO_TRIPLE_BUFFER:
793             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
794             shandle.engineOptions.audioTripleBuffer = (value != 0);
795             break;
796 
797         case CB::ENGINE_OPTION_AUDIO_DRIVER:
798             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr,);
799 
800             if (shandle.engineOptions.audioDriver != nullptr)
801                 delete[] shandle.engineOptions.audioDriver;
802 
803             shandle.engineOptions.audioDriver = carla_strdup_safe(valueStr);
804             break;
805 
806         case CB::ENGINE_OPTION_AUDIO_DEVICE:
807             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr,);
808 
809             if (shandle.engineOptions.audioDevice != nullptr)
810                 delete[] shandle.engineOptions.audioDevice;
811 
812             shandle.engineOptions.audioDevice = carla_strdup_safe(valueStr);
813             break;
814 
815 #ifndef BUILD_BRIDGE
816         case CB::ENGINE_OPTION_OSC_ENABLED:
817             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
818             shandle.engineOptions.oscEnabled = (value != 0);
819             break;
820 
821         case CB::ENGINE_OPTION_OSC_PORT_TCP:
822             CARLA_SAFE_ASSERT_RETURN(value <= 0 || value >= 1024,);
823             shandle.engineOptions.oscPortTCP = value;
824             break;
825 
826         case CB::ENGINE_OPTION_OSC_PORT_UDP:
827             CARLA_SAFE_ASSERT_RETURN(value <= 0 || value >= 1024,);
828             shandle.engineOptions.oscPortUDP = value;
829             break;
830 #endif
831 
832         case CB::ENGINE_OPTION_FILE_PATH:
833             CARLA_SAFE_ASSERT_RETURN(value > CB::FILE_NONE,);
834             CARLA_SAFE_ASSERT_RETURN(value <= CB::FILE_MIDI,);
835             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr,);
836 
837             switch (value)
838             {
839             case CB::FILE_AUDIO:
840                 if (shandle.engineOptions.pathAudio != nullptr)
841                     delete[] shandle.engineOptions.pathAudio;
842                 shandle.engineOptions.pathAudio = carla_strdup_safe(valueStr);
843                 break;
844             case CB::FILE_MIDI:
845                 if (shandle.engineOptions.pathMIDI != nullptr)
846                     delete[] shandle.engineOptions.pathMIDI;
847                 shandle.engineOptions.pathMIDI = carla_strdup_safe(valueStr);
848                 break;
849             }
850             break;
851 
852         case CB::ENGINE_OPTION_PLUGIN_PATH:
853             CARLA_SAFE_ASSERT_RETURN(value > CB::PLUGIN_NONE,);
854             CARLA_SAFE_ASSERT_RETURN(value <= CB::PLUGIN_SFZ,);
855             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr,);
856 
857             switch (value)
858             {
859             case CB::PLUGIN_LADSPA:
860                 if (shandle.engineOptions.pathLADSPA != nullptr)
861                     delete[] shandle.engineOptions.pathLADSPA;
862                 shandle.engineOptions.pathLADSPA = carla_strdup_safe(valueStr);
863                 break;
864             case CB::PLUGIN_DSSI:
865                 if (shandle.engineOptions.pathDSSI != nullptr)
866                     delete[] shandle.engineOptions.pathDSSI;
867                 shandle.engineOptions.pathDSSI = carla_strdup_safe(valueStr);
868                 break;
869             case CB::PLUGIN_LV2:
870                 if (shandle.engineOptions.pathLV2 != nullptr)
871                     delete[] shandle.engineOptions.pathLV2;
872                 shandle.engineOptions.pathLV2 = carla_strdup_safe(valueStr);
873                 break;
874             case CB::PLUGIN_VST2:
875                 if (shandle.engineOptions.pathVST2 != nullptr)
876                     delete[] shandle.engineOptions.pathVST2;
877                 shandle.engineOptions.pathVST2 = carla_strdup_safe(valueStr);
878                 break;
879             case CB::PLUGIN_VST3:
880                 if (shandle.engineOptions.pathVST3 != nullptr)
881                     delete[] shandle.engineOptions.pathVST3;
882                 shandle.engineOptions.pathVST3 = carla_strdup_safe(valueStr);
883                 break;
884             case CB::PLUGIN_SF2:
885                 if (shandle.engineOptions.pathSF2 != nullptr)
886                     delete[] shandle.engineOptions.pathSF2;
887                 shandle.engineOptions.pathSF2 = carla_strdup_safe(valueStr);
888                 break;
889             case CB::PLUGIN_SFZ:
890                 if (shandle.engineOptions.pathSFZ != nullptr)
891                     delete[] shandle.engineOptions.pathSFZ;
892                 shandle.engineOptions.pathSFZ = carla_strdup_safe(valueStr);
893                 break;
894             }
895             break;
896 
897         case CB::ENGINE_OPTION_PATH_BINARIES:
898             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',);
899 
900             if (shandle.engineOptions.binaryDir != nullptr)
901                 delete[] shandle.engineOptions.binaryDir;
902 
903             shandle.engineOptions.binaryDir = carla_strdup_safe(valueStr);
904             break;
905 
906         case CB::ENGINE_OPTION_PATH_RESOURCES:
907             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',);
908 
909             if (shandle.engineOptions.resourceDir != nullptr)
910                 delete[] shandle.engineOptions.resourceDir;
911 
912             shandle.engineOptions.resourceDir = carla_strdup_safe(valueStr);
913             break;
914 
915         case CB::ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR:
916             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
917             shandle.engineOptions.preventBadBehaviour = (value != 0);
918             break;
919 
920         case CB::ENGINE_OPTION_FRONTEND_BACKGROUND_COLOR:
921             shandle.engineOptions.bgColor = static_cast<uint>(value);
922             break;
923 
924         case CB::ENGINE_OPTION_FRONTEND_FOREGROUND_COLOR:
925             shandle.engineOptions.fgColor = static_cast<uint>(value);
926             break;
927 
928         case CB::ENGINE_OPTION_FRONTEND_UI_SCALE:
929             CARLA_SAFE_ASSERT_RETURN(value > 0,);
930             shandle.engineOptions.uiScale = static_cast<float>(value) / 1000;
931             break;
932 
933         case CB::ENGINE_OPTION_FRONTEND_WIN_ID: {
934             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',);
935             const long long winId(std::strtoll(valueStr, nullptr, 16));
936             CARLA_SAFE_ASSERT_RETURN(winId >= 0,);
937             shandle.engineOptions.frontendWinId = static_cast<uintptr_t>(winId);
938         }   break;
939 
940 #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN)
941         case CB::ENGINE_OPTION_WINE_EXECUTABLE:
942             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',);
943 
944             if (shandle.engineOptions.wine.executable != nullptr)
945                 delete[] shandle.engineOptions.wine.executable;
946 
947             shandle.engineOptions.wine.executable = carla_strdup_safe(valueStr);
948             break;
949 
950         case CB::ENGINE_OPTION_WINE_AUTO_PREFIX:
951             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
952             shandle.engineOptions.wine.autoPrefix = (value != 0);
953             break;
954 
955         case CB::ENGINE_OPTION_WINE_FALLBACK_PREFIX:
956             CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',);
957 
958             if (shandle.engineOptions.wine.fallbackPrefix != nullptr)
959                 delete[] shandle.engineOptions.wine.fallbackPrefix;
960 
961             shandle.engineOptions.wine.fallbackPrefix = carla_strdup_safe(valueStr);
962             break;
963 
964         case CB::ENGINE_OPTION_WINE_RT_PRIO_ENABLED:
965             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
966             shandle.engineOptions.wine.rtPrio = (value != 0);
967             break;
968 
969         case CB::ENGINE_OPTION_WINE_BASE_RT_PRIO:
970             CARLA_SAFE_ASSERT_RETURN(value >= 1 && value <= 89,);
971             shandle.engineOptions.wine.baseRtPrio = value;
972             break;
973 
974         case CB::ENGINE_OPTION_WINE_SERVER_RT_PRIO:
975             CARLA_SAFE_ASSERT_RETURN(value >= 1 && value <= 99,);
976             shandle.engineOptions.wine.serverRtPrio = value;
977             break;
978 #endif
979 
980 #ifndef BUILD_BRIDGE
981         case CB::ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT:
982             shandle.logThreadEnabled = (value != 0);
983             break;
984 #endif
985 
986         case CB::ENGINE_OPTION_CLIENT_NAME_PREFIX:
987             if (shandle.engineOptions.clientNamePrefix != nullptr)
988                 delete[] shandle.engineOptions.clientNamePrefix;
989 
990             shandle.engineOptions.clientNamePrefix = valueStr != nullptr && valueStr[0] != '\0'
991                                                    ? carla_strdup_safe(valueStr)
992                                                    : nullptr;
993             break;
994 
995         case CB::ENGINE_OPTION_PLUGINS_ARE_STANDALONE:
996             CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
997             shandle.engineOptions.pluginsAreStandalone = (value != 0);
998             break;
999         }
1000     }
1001 
1002     if (handle->engine != nullptr)
1003         handle->engine->setOption(option, value, valueStr);
1004 }
1005 
carla_set_file_callback(CarlaHostHandle handle,FileCallbackFunc func,void * ptr)1006 void carla_set_file_callback(CarlaHostHandle handle, FileCallbackFunc func, void* ptr)
1007 {
1008     carla_debug("carla_set_file_callback(%p, %p, %p)", handle, func, ptr);
1009 
1010     if (handle->isStandalone)
1011     {
1012         CarlaHostStandalone& shandle((CarlaHostStandalone&)*handle);
1013 
1014         shandle.fileCallback    = func;
1015         shandle.fileCallbackPtr = ptr;
1016     }
1017 
1018     if (handle->engine != nullptr)
1019         handle->engine->setFileCallback(func, ptr);
1020 }
1021 
1022 // --------------------------------------------------------------------------------------------------------------------
1023 
carla_load_file(CarlaHostHandle handle,const char * filename)1024 bool carla_load_file(CarlaHostHandle handle, const char* filename)
1025 {
1026     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
1027     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1028 
1029     carla_debug("carla_load_file(%p, \"%s\")", handle, filename);
1030 
1031     return handle->engine->loadFile(filename);
1032 }
1033 
carla_load_project(CarlaHostHandle handle,const char * filename)1034 bool carla_load_project(CarlaHostHandle handle, const char* filename)
1035 {
1036     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
1037     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1038 
1039     carla_debug("carla_load_project(%p, \"%s\")", handle, filename);
1040 
1041     return handle->engine->loadProject(filename, true);
1042 }
1043 
carla_save_project(CarlaHostHandle handle,const char * filename)1044 bool carla_save_project(CarlaHostHandle handle, const char* filename)
1045 {
1046     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
1047     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1048 
1049     carla_debug("carla_save_project(%p, \"%s\")", handle, filename);
1050 
1051     return handle->engine->saveProject(filename, true);
1052 }
1053 
1054 #ifndef BUILD_BRIDGE
carla_get_current_project_folder(CarlaHostHandle handle)1055 const char* carla_get_current_project_folder(CarlaHostHandle handle)
1056 {
1057     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr);
1058 
1059     carla_debug("carla_get_current_project_folder(%p)", handle);
1060 
1061     if (const char* const ret = handle->engine->getCurrentProjectFolder())
1062         return ret;
1063 
1064     return gNullCharPtr;
1065 }
1066 
carla_get_current_project_filename(CarlaHostHandle handle)1067 const char* carla_get_current_project_filename(CarlaHostHandle handle)
1068 {
1069     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->isStandalone, gNullCharPtr);
1070 
1071     carla_debug("carla_get_current_project_filename(%p)", handle);
1072 
1073     if (const char* const ret = handle->engine->getCurrentProjectFilename())
1074         return ret;
1075 
1076     return gNullCharPtr;
1077 }
1078 
carla_clear_project_filename(CarlaHostHandle handle)1079 void carla_clear_project_filename(CarlaHostHandle handle)
1080 {
1081     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
1082 
1083     carla_debug("carla_clear_project_filename(%p)", handle);
1084 
1085     handle->engine->clearCurrentProjectFilename();
1086 }
1087 
1088 // --------------------------------------------------------------------------------------------------------------------
1089 
carla_patchbay_connect(CarlaHostHandle handle,bool external,uint groupIdA,uint portIdA,uint groupIdB,uint portIdB)1090 bool carla_patchbay_connect(CarlaHostHandle handle, bool external, uint groupIdA, uint portIdA, uint groupIdB, uint portIdB)
1091 {
1092     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1093 
1094     carla_debug("carla_patchbay_connect(%p, %s, %u, %u, %u, %u)",
1095                 handle, bool2str(external), groupIdA, portIdA, groupIdB, portIdB);
1096 
1097     return handle->engine->patchbayConnect(external, groupIdA, portIdA, groupIdB, portIdB);
1098 }
1099 
carla_patchbay_disconnect(CarlaHostHandle handle,bool external,uint connectionId)1100 bool carla_patchbay_disconnect(CarlaHostHandle handle, bool external, uint connectionId)
1101 {
1102     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1103 
1104     carla_debug("carla_patchbay_disconnect(%p, %s, %i)", handle, bool2str(external), connectionId);
1105 
1106     return handle->engine->patchbayDisconnect(external, connectionId);
1107 }
1108 
carla_patchbay_set_group_pos(CarlaHostHandle handle,bool external,uint groupId,int x1,int y1,int x2,int y2)1109 bool carla_patchbay_set_group_pos(CarlaHostHandle handle, bool external, uint groupId, int x1, int y1, int x2, int y2)
1110 {
1111     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr && handle->engine->isRunning(),
1112                                              "Engine is not running", false);
1113 
1114     carla_debug("carla_patchbay_set_group_pos(%p, %s, %u, %i, %i, %i, %i)",
1115                 handle, bool2str(external), groupId, x1, y1, x2, y2);
1116 
1117     if (handle->engine->isAboutToClose())
1118         return true;
1119 
1120     return handle->engine->patchbaySetGroupPos(false, true, external, groupId, x1, y1, x2, y2);
1121 }
1122 
carla_patchbay_refresh(CarlaHostHandle handle,bool external)1123 bool carla_patchbay_refresh(CarlaHostHandle handle, bool external)
1124 {
1125     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1126 
1127     carla_debug("carla_patchbay_refresh(%p, %s)", handle, bool2str(external));
1128 
1129     return handle->engine->patchbayRefresh(true, false, external);
1130 }
1131 
1132 // --------------------------------------------------------------------------------------------------------------------
1133 
carla_transport_play(CarlaHostHandle handle)1134 void carla_transport_play(CarlaHostHandle handle)
1135 {
1136     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(),);
1137 
1138     carla_debug("carla_transport_play(%p)", handle);
1139 
1140     handle->engine->transportPlay();
1141 }
1142 
carla_transport_pause(CarlaHostHandle handle)1143 void carla_transport_pause(CarlaHostHandle handle)
1144 {
1145     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(),);
1146 
1147     carla_debug("carla_transport_pause(%p)", handle);
1148 
1149     handle->engine->transportPause();
1150 }
1151 
carla_transport_bpm(CarlaHostHandle handle,double bpm)1152 void carla_transport_bpm(CarlaHostHandle handle, double bpm)
1153 {
1154     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(),);
1155 
1156     carla_debug("carla_transport_bpm(%p, %f)", handle, bpm);
1157 
1158     handle->engine->transportBPM(bpm);
1159 }
1160 
carla_transport_relocate(CarlaHostHandle handle,uint64_t frame)1161 void carla_transport_relocate(CarlaHostHandle handle, uint64_t frame)
1162 {
1163     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(),);
1164 
1165     carla_debug("carla_transport_relocate(%p, %i)", handle, frame);
1166 
1167     handle->engine->transportRelocate(frame);
1168 }
1169 
carla_get_current_transport_frame(CarlaHostHandle handle)1170 uint64_t carla_get_current_transport_frame(CarlaHostHandle handle)
1171 {
1172     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(), 0);
1173 
1174     return handle->engine->getTimeInfo().frame;
1175 }
1176 
carla_get_transport_info(CarlaHostHandle handle)1177 const CarlaTransportInfo* carla_get_transport_info(CarlaHostHandle handle)
1178 {
1179     static CarlaTransportInfo retTransInfo;
1180     retTransInfo.clear();
1181 
1182     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(), &retTransInfo);
1183 
1184     const CB::EngineTimeInfo& timeInfo(handle->engine->getTimeInfo());
1185 
1186     retTransInfo.playing = timeInfo.playing;
1187     retTransInfo.frame   = timeInfo.frame;
1188 
1189     if (timeInfo.bbt.valid)
1190     {
1191         retTransInfo.bar  = timeInfo.bbt.bar;
1192         retTransInfo.beat = timeInfo.bbt.beat;
1193         retTransInfo.tick = static_cast<int32_t>(timeInfo.bbt.tick + 0.5);
1194         retTransInfo.bpm  = timeInfo.bbt.beatsPerMinute;
1195     }
1196 
1197     return &retTransInfo;
1198 }
1199 #endif
1200 
1201 // --------------------------------------------------------------------------------------------------------------------
1202 
carla_get_current_plugin_count(CarlaHostHandle handle)1203 uint32_t carla_get_current_plugin_count(CarlaHostHandle handle)
1204 {
1205     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1206 
1207     carla_debug("carla_get_current_plugin_count(%p)", handle);
1208 
1209     return handle->engine->getCurrentPluginCount();
1210 }
1211 
carla_get_max_plugin_number(CarlaHostHandle handle)1212 uint32_t carla_get_max_plugin_number(CarlaHostHandle handle)
1213 {
1214     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1215 
1216     carla_debug("carla_get_max_plugin_number(%p)", handle);
1217 
1218     return handle->engine->getMaxPluginNumber();
1219 }
1220 
1221 // --------------------------------------------------------------------------------------------------------------------
1222 
carla_add_plugin(CarlaHostHandle handle,BinaryType btype,PluginType ptype,const char * filename,const char * name,const char * label,int64_t uniqueId,const void * extraPtr,uint options)1223 bool carla_add_plugin(CarlaHostHandle handle,
1224                       BinaryType btype, PluginType ptype,
1225                       const char* filename, const char* name, const char* label, int64_t uniqueId,
1226                       const void* extraPtr, uint options)
1227 {
1228     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1229 
1230     carla_debug("carla_add_plugin(%p, %i:%s, %i:%s, \"%s\", \"%s\", \"%s\", " P_INT64 ", %p, %u)",
1231                 handle,
1232                 btype, CB::BinaryType2Str(btype),
1233                 ptype, CB::PluginType2Str(ptype),
1234                 filename, name, label, uniqueId, extraPtr, options);
1235 
1236     return handle->engine->addPlugin(btype, ptype, filename, name, label, uniqueId, extraPtr, options);
1237 }
1238 
carla_remove_plugin(CarlaHostHandle handle,uint pluginId)1239 bool carla_remove_plugin(CarlaHostHandle handle, uint pluginId)
1240 {
1241     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1242 
1243     carla_debug("carla_remove_plugin(%p, %i)", handle, pluginId);
1244 
1245     return handle->engine->removePlugin(pluginId);
1246 }
1247 
carla_remove_all_plugins(CarlaHostHandle handle)1248 bool carla_remove_all_plugins(CarlaHostHandle handle)
1249 {
1250     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1251 
1252     carla_debug("carla_remove_all_plugins(%p)", handle);
1253 
1254     return handle->engine->removeAllPlugins();
1255 }
1256 
1257 #ifndef BUILD_BRIDGE
carla_rename_plugin(CarlaHostHandle handle,uint pluginId,const char * newName)1258 bool carla_rename_plugin(CarlaHostHandle handle, uint pluginId, const char* newName)
1259 {
1260     CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', false);
1261     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1262 
1263     carla_debug("carla_rename_plugin(%p, %i, \"%s\")", handle, pluginId, newName);
1264 
1265     return handle->engine->renamePlugin(pluginId, newName);
1266 }
1267 
carla_clone_plugin(CarlaHostHandle handle,uint pluginId)1268 bool carla_clone_plugin(CarlaHostHandle handle, uint pluginId)
1269 {
1270     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1271 
1272     carla_debug("carla_clone_plugin(%p, %i)", handle, pluginId);
1273 
1274     return handle->engine->clonePlugin(pluginId);
1275 }
1276 
carla_replace_plugin(CarlaHostHandle handle,uint pluginId)1277 bool carla_replace_plugin(CarlaHostHandle handle, uint pluginId)
1278 {
1279     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1280 
1281     carla_debug("carla_replace_plugin(%p, %i)", handle, pluginId);
1282 
1283     return handle->engine->replacePlugin(pluginId);
1284 }
1285 
carla_switch_plugins(CarlaHostHandle handle,uint pluginIdA,uint pluginIdB)1286 bool carla_switch_plugins(CarlaHostHandle handle, uint pluginIdA, uint pluginIdB)
1287 {
1288     CARLA_SAFE_ASSERT_RETURN(pluginIdA != pluginIdB, false);
1289     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1290 
1291     carla_debug("carla_switch_plugins(%p, %i, %i)", handle, pluginIdA, pluginIdB);
1292 
1293     return handle->engine->switchPlugins(pluginIdA, pluginIdB);
1294 }
1295 #endif
1296 
1297 // --------------------------------------------------------------------------------------------------------------------
1298 
carla_load_plugin_state(CarlaHostHandle handle,uint pluginId,const char * filename)1299 bool carla_load_plugin_state(CarlaHostHandle handle, uint pluginId, const char* filename)
1300 {
1301     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
1302     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr
1303                                           && handle->engine->isRunning(), "Engine is not running", false);
1304 
1305     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1306         return plugin->loadStateFromFile(filename);
1307 
1308     return false;
1309 }
1310 
carla_save_plugin_state(CarlaHostHandle handle,uint pluginId,const char * filename)1311 bool carla_save_plugin_state(CarlaHostHandle handle, uint pluginId, const char* filename)
1312 {
1313     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
1314     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1315 
1316     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1317         return plugin->saveStateToFile(filename);
1318 
1319     return false;
1320 }
1321 
carla_export_plugin_lv2(CarlaHostHandle handle,uint pluginId,const char * lv2path)1322 bool carla_export_plugin_lv2(CarlaHostHandle handle, uint pluginId, const char* lv2path)
1323 {
1324     CARLA_SAFE_ASSERT_RETURN(lv2path != nullptr && lv2path[0] != '\0', false);
1325     CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine != nullptr, "Engine is not initialized", false);
1326 
1327     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1328         return plugin->exportAsLV2(lv2path);
1329 
1330     return false;
1331 }
1332 
1333 // --------------------------------------------------------------------------------------------------------------------
1334 
carla_get_plugin_info(CarlaHostHandle handle,uint pluginId)1335 const CarlaPluginInfo* carla_get_plugin_info(CarlaHostHandle handle, uint pluginId)
1336 {
1337     static CarlaPluginInfo retInfo;
1338 
1339     // reset
1340     retInfo.type             = CB::PLUGIN_NONE;
1341     retInfo.category         = CB::PLUGIN_CATEGORY_NONE;
1342     retInfo.hints            = 0x0;
1343     retInfo.optionsAvailable = 0x0;
1344     retInfo.optionsEnabled   = 0x0;
1345     retInfo.filename         = gNullCharPtr;
1346     retInfo.name             = gNullCharPtr;
1347     retInfo.iconName         = gNullCharPtr;
1348     retInfo.uniqueId         = 0;
1349 
1350     // cleanup
1351     if (retInfo.label != gNullCharPtr)
1352     {
1353         delete[] retInfo.label;
1354         retInfo.label = gNullCharPtr;
1355     }
1356 
1357     if (retInfo.maker != gNullCharPtr)
1358     {
1359         delete[] retInfo.maker;
1360         retInfo.maker = gNullCharPtr;
1361     }
1362 
1363     if (retInfo.copyright != gNullCharPtr)
1364     {
1365         delete[] retInfo.copyright;
1366         retInfo.copyright = gNullCharPtr;
1367     }
1368 
1369     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
1370 
1371     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1372     {
1373         char strBuf[STR_MAX+1];
1374         carla_zeroChars(strBuf, STR_MAX+1);
1375 
1376         retInfo.type     = plugin->getType();
1377         retInfo.category = plugin->getCategory();
1378         retInfo.hints    = plugin->getHints();
1379         retInfo.filename = plugin->getFilename();
1380         retInfo.name     = plugin->getName();
1381         retInfo.iconName = plugin->getIconName();
1382         retInfo.uniqueId = plugin->getUniqueId();
1383 
1384         retInfo.optionsAvailable = plugin->getOptionsAvailable();
1385         retInfo.optionsEnabled   = plugin->getOptionsEnabled();
1386 
1387         if (plugin->getLabel(strBuf))
1388             retInfo.label = carla_strdup_safe(strBuf);
1389         if (plugin->getMaker(strBuf))
1390             retInfo.maker = carla_strdup_safe(strBuf);
1391         if (plugin->getCopyright(strBuf))
1392             retInfo.copyright = carla_strdup_safe(strBuf);
1393 
1394         checkStringPtr(retInfo.filename);
1395         checkStringPtr(retInfo.name);
1396         checkStringPtr(retInfo.iconName);
1397         checkStringPtr(retInfo.label);
1398         checkStringPtr(retInfo.maker);
1399         checkStringPtr(retInfo.copyright);
1400     }
1401 
1402     return &retInfo;
1403 }
1404 
carla_get_audio_port_count_info(CarlaHostHandle handle,uint pluginId)1405 const CarlaPortCountInfo* carla_get_audio_port_count_info(CarlaHostHandle handle, uint pluginId)
1406 {
1407     static CarlaPortCountInfo retInfo;
1408     carla_zeroStruct(retInfo);
1409 
1410     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
1411 
1412     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1413     {
1414         retInfo.ins   = plugin->getAudioInCount();
1415         retInfo.outs  = plugin->getAudioOutCount();
1416     }
1417 
1418     return &retInfo;
1419 }
1420 
carla_get_midi_port_count_info(CarlaHostHandle handle,uint pluginId)1421 const CarlaPortCountInfo* carla_get_midi_port_count_info(CarlaHostHandle handle, uint pluginId)
1422 {
1423     static CarlaPortCountInfo retInfo;
1424     carla_zeroStruct(retInfo);
1425 
1426     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
1427 
1428     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1429     {
1430         retInfo.ins   = plugin->getMidiInCount();
1431         retInfo.outs  = plugin->getMidiOutCount();
1432     }
1433 
1434     return &retInfo;
1435 }
1436 
carla_get_parameter_count_info(CarlaHostHandle handle,uint pluginId)1437 const CarlaPortCountInfo* carla_get_parameter_count_info(CarlaHostHandle handle, uint pluginId)
1438 {
1439     static CarlaPortCountInfo retInfo;
1440     carla_zeroStruct(retInfo);
1441 
1442     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
1443 
1444     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1445         plugin->getParameterCountInfo(retInfo.ins, retInfo.outs);
1446 
1447     return &retInfo;
1448 }
1449 
carla_get_parameter_info(CarlaHostHandle handle,uint pluginId,uint32_t parameterId)1450 const CarlaParameterInfo* carla_get_parameter_info(CarlaHostHandle handle, uint pluginId, uint32_t parameterId)
1451 {
1452     static CarlaParameterInfo retInfo;
1453 
1454     // reset
1455     retInfo.scalePointCount = 0;
1456 
1457     // cleanup
1458     if (retInfo.name != gNullCharPtr)
1459     {
1460         delete[] retInfo.name;
1461         retInfo.name = gNullCharPtr;
1462     }
1463 
1464     if (retInfo.symbol != gNullCharPtr)
1465     {
1466         delete[] retInfo.symbol;
1467         retInfo.symbol = gNullCharPtr;
1468     }
1469 
1470     if (retInfo.unit != gNullCharPtr)
1471     {
1472         delete[] retInfo.unit;
1473         retInfo.unit = gNullCharPtr;
1474     }
1475 
1476     if (retInfo.comment != gNullCharPtr)
1477     {
1478         delete[] retInfo.comment;
1479         retInfo.comment = gNullCharPtr;
1480     }
1481 
1482     if (retInfo.groupName != gNullCharPtr)
1483     {
1484         delete[] retInfo.groupName;
1485         retInfo.groupName = gNullCharPtr;
1486     }
1487 
1488     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
1489 
1490     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1491     {
1492         char strBuf[STR_MAX+1];
1493         carla_zeroChars(strBuf, STR_MAX+1);
1494 
1495         retInfo.scalePointCount = plugin->getParameterScalePointCount(parameterId);
1496 
1497         if (plugin->getParameterName(parameterId, strBuf))
1498         {
1499             retInfo.name = carla_strdup_safe(strBuf);
1500             carla_zeroChars(strBuf, STR_MAX+1);
1501         }
1502 
1503         if (plugin->getParameterSymbol(parameterId, strBuf))
1504         {
1505             retInfo.symbol = carla_strdup_safe(strBuf);
1506             carla_zeroChars(strBuf, STR_MAX+1);
1507         }
1508 
1509         if (plugin->getParameterUnit(parameterId, strBuf))
1510         {
1511             retInfo.unit = carla_strdup_safe(strBuf);
1512             carla_zeroChars(strBuf, STR_MAX+1);
1513         }
1514 
1515         if (plugin->getParameterComment(parameterId, strBuf))
1516         {
1517             retInfo.comment = carla_strdup_safe(strBuf);
1518             carla_zeroChars(strBuf, STR_MAX+1);
1519         }
1520 
1521         if (plugin->getParameterGroupName(parameterId, strBuf))
1522         {
1523             retInfo.groupName = carla_strdup_safe(strBuf);
1524             carla_zeroChars(strBuf, STR_MAX+1);
1525         }
1526 
1527         checkStringPtr(retInfo.name);
1528         checkStringPtr(retInfo.symbol);
1529         checkStringPtr(retInfo.unit);
1530         checkStringPtr(retInfo.comment);
1531         checkStringPtr(retInfo.groupName);
1532     }
1533 
1534     return &retInfo;
1535 }
1536 
carla_get_parameter_scalepoint_info(CarlaHostHandle handle,uint pluginId,uint32_t parameterId,uint32_t scalePointId)1537 const CarlaScalePointInfo* carla_get_parameter_scalepoint_info(CarlaHostHandle handle,
1538                                                                uint pluginId,
1539                                                                uint32_t parameterId,
1540                                                                uint32_t scalePointId)
1541 {
1542     CARLA_ASSERT(handle->engine != nullptr);
1543 
1544     static CarlaScalePointInfo retInfo;
1545 
1546     // reset
1547     retInfo.value = 0.0f;
1548 
1549     // cleanup
1550     if (retInfo.label != gNullCharPtr)
1551     {
1552         delete[] retInfo.label;
1553         retInfo.label = gNullCharPtr;
1554     }
1555 
1556     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retInfo);
1557 
1558     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1559     {
1560         char strBuf[STR_MAX+1];
1561 
1562         retInfo.value = plugin->getParameterScalePointValue(parameterId, scalePointId);
1563 
1564         carla_zeroChars(strBuf, STR_MAX+1);
1565         if (plugin->getParameterScalePointLabel(parameterId, scalePointId, strBuf))
1566             retInfo.label = carla_strdup_safe(strBuf);
1567 
1568         checkStringPtr(retInfo.label);
1569     }
1570 
1571     return &retInfo;
1572 }
1573 
1574 // --------------------------------------------------------------------------------------------------------------------
1575 
carla_get_parameter_data(CarlaHostHandle handle,uint pluginId,uint32_t parameterId)1576 const ParameterData* carla_get_parameter_data(CarlaHostHandle handle, uint pluginId, uint32_t parameterId)
1577 {
1578     static ParameterData retParamData;
1579 
1580     // reset
1581     retParamData.type        = CB::PARAMETER_UNKNOWN;
1582     retParamData.hints       = 0x0;
1583     retParamData.index       = CB::PARAMETER_NULL;
1584     retParamData.rindex      = -1;
1585     retParamData.midiChannel = 0;
1586     retParamData.mappedControlIndex = CB::CONTROL_INDEX_NONE;
1587     retParamData.mappedMinimum = 0.0f;
1588     retParamData.mappedMaximum = 0.0f;
1589 
1590     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retParamData);
1591 
1592     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1593     {
1594         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(), &retParamData);
1595 
1596         const ParameterData& pluginParamData(plugin->getParameterData(parameterId));
1597         retParamData.type        = pluginParamData.type;
1598         retParamData.hints       = pluginParamData.hints;
1599         retParamData.index       = pluginParamData.index;
1600         retParamData.rindex      = pluginParamData.rindex;
1601         retParamData.midiChannel = pluginParamData.midiChannel;
1602         retParamData.mappedControlIndex = pluginParamData.mappedControlIndex;
1603         retParamData.mappedMinimum = pluginParamData.mappedMinimum;
1604         retParamData.mappedMaximum = pluginParamData.mappedMaximum;
1605     }
1606 
1607     return &retParamData;
1608 }
1609 
carla_get_parameter_ranges(CarlaHostHandle handle,uint pluginId,uint32_t parameterId)1610 const ParameterRanges* carla_get_parameter_ranges(CarlaHostHandle handle, uint pluginId, uint32_t parameterId)
1611 {
1612     static ParameterRanges retParamRanges;
1613 
1614     // reset
1615     retParamRanges.def       = 0.0f;
1616     retParamRanges.min       = 0.0f;
1617     retParamRanges.max       = 1.0f;
1618     retParamRanges.step      = 0.01f;
1619     retParamRanges.stepSmall = 0.0001f;
1620     retParamRanges.stepLarge = 0.1f;
1621 
1622     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retParamRanges);
1623 
1624     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1625     {
1626         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(), &retParamRanges);
1627 
1628         const ParameterRanges& pluginParamRanges(plugin->getParameterRanges(parameterId));
1629         retParamRanges.def       = pluginParamRanges.def;
1630         retParamRanges.min       = pluginParamRanges.min;
1631         retParamRanges.max       = pluginParamRanges.max;
1632         retParamRanges.step      = pluginParamRanges.step;
1633         retParamRanges.stepSmall = pluginParamRanges.stepSmall;
1634         retParamRanges.stepLarge = pluginParamRanges.stepLarge;
1635     }
1636 
1637     return &retParamRanges;
1638 }
1639 
carla_get_midi_program_data(CarlaHostHandle handle,uint pluginId,uint32_t midiProgramId)1640 const MidiProgramData* carla_get_midi_program_data(CarlaHostHandle handle, uint pluginId, uint32_t midiProgramId)
1641 {
1642     static MidiProgramData retMidiProgData = { 0, 0, gNullCharPtr };
1643 
1644     // reset
1645     retMidiProgData.bank    = 0;
1646     retMidiProgData.program = 0;
1647 
1648     if (retMidiProgData.name != gNullCharPtr)
1649     {
1650         delete[] retMidiProgData.name;
1651         retMidiProgData.name = gNullCharPtr;
1652     }
1653 
1654     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retMidiProgData);
1655 
1656     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1657     {
1658         CARLA_SAFE_ASSERT_RETURN(midiProgramId < plugin->getMidiProgramCount(), &retMidiProgData);
1659 
1660         const MidiProgramData& pluginMidiProgData(plugin->getMidiProgramData(midiProgramId));
1661         retMidiProgData.bank    = pluginMidiProgData.bank;
1662         retMidiProgData.program = pluginMidiProgData.program;
1663 
1664         if (pluginMidiProgData.name != nullptr)
1665         {
1666             retMidiProgData.name = carla_strdup_safe(pluginMidiProgData.name);
1667             checkStringPtr(retMidiProgData.name);
1668         }
1669         else
1670         {
1671             retMidiProgData.name = gNullCharPtr;
1672         }
1673     }
1674 
1675     return &retMidiProgData;
1676 }
1677 
carla_get_custom_data(CarlaHostHandle handle,uint pluginId,uint32_t customDataId)1678 const CustomData* carla_get_custom_data(CarlaHostHandle handle, uint pluginId, uint32_t customDataId)
1679 {
1680     static CustomData retCustomData = { gNullCharPtr, gNullCharPtr, gNullCharPtr };
1681 
1682     // reset
1683     if (retCustomData.type != gNullCharPtr)
1684     {
1685         delete[] retCustomData.type;
1686         retCustomData.type = gNullCharPtr;
1687     }
1688 
1689     if (retCustomData.key != gNullCharPtr)
1690     {
1691         delete[] retCustomData.key;
1692         retCustomData.key = gNullCharPtr;
1693     }
1694 
1695     if (retCustomData.value != gNullCharPtr)
1696     {
1697         delete[] retCustomData.value;
1698         retCustomData.value = gNullCharPtr;
1699     }
1700 
1701     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, &retCustomData);
1702 
1703     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1704     {
1705         CARLA_SAFE_ASSERT_RETURN(customDataId < plugin->getCustomDataCount(), &retCustomData)
1706 
1707         const CustomData& pluginCustomData(plugin->getCustomData(customDataId));
1708         retCustomData.type  = carla_strdup_safe(pluginCustomData.type);
1709         retCustomData.key   = carla_strdup_safe(pluginCustomData.key);
1710         retCustomData.value = carla_strdup_safe(pluginCustomData.value);
1711         checkStringPtr(retCustomData.type);
1712         checkStringPtr(retCustomData.key);
1713         checkStringPtr(retCustomData.value);
1714     }
1715 
1716     return &retCustomData;
1717 }
1718 
carla_get_custom_data_value(CarlaHostHandle handle,uint pluginId,const char * type,const char * key)1719 const char* carla_get_custom_data_value(CarlaHostHandle handle, uint pluginId, const char* type, const char* key)
1720 {
1721     CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0', gNullCharPtr);
1722     CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', gNullCharPtr);
1723     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr);
1724 
1725     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1726     {
1727         const uint32_t count = plugin->getCustomDataCount();
1728 
1729         if (count == 0)
1730             return gNullCharPtr;
1731 
1732         static CarlaString customDataValue;
1733 
1734         for (uint32_t i=0; i<count; ++i)
1735         {
1736             const CustomData& pluginCustomData(plugin->getCustomData(i));
1737 
1738             if (std::strcmp(pluginCustomData.type, type) != 0)
1739                 continue;
1740             if (std::strcmp(pluginCustomData.key, key) != 0)
1741                 continue;
1742 
1743             customDataValue = pluginCustomData.value;
1744             return customDataValue.buffer();
1745         }
1746     }
1747 
1748     return gNullCharPtr;
1749 }
1750 
carla_get_chunk_data(CarlaHostHandle handle,uint pluginId)1751 const char* carla_get_chunk_data(CarlaHostHandle handle, uint pluginId)
1752 {
1753     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr);
1754 
1755     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1756     {
1757         CARLA_SAFE_ASSERT_RETURN(plugin->getOptionsEnabled() & CB::PLUGIN_OPTION_USE_CHUNKS, gNullCharPtr);
1758 
1759         void* data = nullptr;
1760         const std::size_t dataSize(plugin->getChunkData(&data));
1761         CARLA_SAFE_ASSERT_RETURN(data != nullptr && dataSize > 0, gNullCharPtr);
1762 
1763         static CarlaString chunkData;
1764 
1765         chunkData = CarlaString::asBase64(data, static_cast<std::size_t>(dataSize));
1766         return chunkData.buffer();
1767     }
1768 
1769     return gNullCharPtr;
1770 }
1771 
1772 // --------------------------------------------------------------------------------------------------------------------
1773 
carla_get_parameter_count(CarlaHostHandle handle,uint pluginId)1774 uint32_t carla_get_parameter_count(CarlaHostHandle handle, uint pluginId)
1775 {
1776     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1777 
1778     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1779         return plugin->getParameterCount();
1780 
1781     return 0;
1782 }
1783 
carla_get_program_count(CarlaHostHandle handle,uint pluginId)1784 uint32_t carla_get_program_count(CarlaHostHandle handle, uint pluginId)
1785 {
1786     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1787 
1788     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1789         return plugin->getProgramCount();
1790 
1791     return 0;
1792 }
1793 
carla_get_midi_program_count(CarlaHostHandle handle,uint pluginId)1794 uint32_t carla_get_midi_program_count(CarlaHostHandle handle, uint pluginId)
1795 {
1796     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1797 
1798     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1799         return plugin->getMidiProgramCount();
1800 
1801     return 0;
1802 }
1803 
carla_get_custom_data_count(CarlaHostHandle handle,uint pluginId)1804 uint32_t carla_get_custom_data_count(CarlaHostHandle handle, uint pluginId)
1805 {
1806     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1807 
1808     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1809         return plugin->getCustomDataCount();
1810 
1811     return 0;
1812 }
1813 
1814 // --------------------------------------------------------------------------------------------------------------------
1815 
carla_get_parameter_text(CarlaHostHandle handle,uint pluginId,uint32_t parameterId)1816 const char* carla_get_parameter_text(CarlaHostHandle handle, uint pluginId, uint32_t parameterId)
1817 {
1818     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr);
1819 
1820     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1821     {
1822         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(), gNullCharPtr);
1823 
1824         static char textBuf[STR_MAX+1];
1825         carla_zeroChars(textBuf, STR_MAX+1);
1826 
1827         if (! plugin->getParameterText(parameterId, textBuf))
1828             textBuf[0] = '\0';
1829 
1830         return textBuf;
1831     }
1832 
1833     return gNullCharPtr;
1834 }
1835 
carla_get_program_name(CarlaHostHandle handle,uint pluginId,uint32_t programId)1836 const char* carla_get_program_name(CarlaHostHandle handle, uint pluginId, uint32_t programId)
1837 {
1838     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, nullptr);
1839 
1840     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1841     {
1842         CARLA_SAFE_ASSERT_RETURN(programId < plugin->getProgramCount(), gNullCharPtr);
1843 
1844         static char programName[STR_MAX+1];
1845         carla_zeroChars(programName, STR_MAX+1);
1846 
1847         if (! plugin->getProgramName(programId, programName))
1848             programName[0] = '\0';
1849 
1850         return programName;
1851     }
1852 
1853     return gNullCharPtr;
1854 }
1855 
carla_get_midi_program_name(CarlaHostHandle handle,uint pluginId,uint32_t midiProgramId)1856 const char* carla_get_midi_program_name(CarlaHostHandle handle, uint pluginId, uint32_t midiProgramId)
1857 {
1858     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr);
1859 
1860     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1861     {
1862         CARLA_SAFE_ASSERT_RETURN(midiProgramId < plugin->getMidiProgramCount(), gNullCharPtr);
1863 
1864         static char midiProgramName[STR_MAX+1];
1865         carla_zeroChars(midiProgramName, STR_MAX+1);
1866 
1867         if (! plugin->getMidiProgramName(midiProgramId, midiProgramName))
1868             midiProgramName[0] = '\0';
1869 
1870         return midiProgramName;
1871     }
1872 
1873     return gNullCharPtr;
1874 }
1875 
carla_get_real_plugin_name(CarlaHostHandle handle,uint pluginId)1876 const char* carla_get_real_plugin_name(CarlaHostHandle handle, uint pluginId)
1877 {
1878     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr);
1879 
1880     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1881     {
1882         static char realPluginName[STR_MAX+1];
1883         carla_zeroChars(realPluginName, STR_MAX+1);
1884 
1885         if (! plugin->getRealName(realPluginName))
1886             realPluginName[0] = '\0';
1887 
1888         return realPluginName;
1889     }
1890 
1891     return gNullCharPtr;
1892 }
1893 
1894 // --------------------------------------------------------------------------------------------------------------------
1895 
carla_get_current_program_index(CarlaHostHandle handle,uint pluginId)1896 int32_t carla_get_current_program_index(CarlaHostHandle handle, uint pluginId)
1897 {
1898     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, -1);
1899 
1900     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1901         return plugin->getCurrentProgram();
1902 
1903     return -1;
1904 }
1905 
carla_get_current_midi_program_index(CarlaHostHandle handle,uint pluginId)1906 int32_t carla_get_current_midi_program_index(CarlaHostHandle handle, uint pluginId)
1907 {
1908     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, -1);
1909 
1910     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1911         return plugin->getCurrentMidiProgram();
1912 
1913     return -1;
1914 }
1915 
1916 // --------------------------------------------------------------------------------------------------------------------
1917 
carla_get_default_parameter_value(CarlaHostHandle handle,uint pluginId,uint32_t parameterId)1918 float carla_get_default_parameter_value(CarlaHostHandle handle, uint pluginId, uint32_t parameterId)
1919 {
1920     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0.0f);
1921 
1922     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1923     {
1924         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(), 0.0f);
1925 
1926         return plugin->getParameterRanges(parameterId).def;
1927     }
1928 
1929     return 0.0f;
1930 }
1931 
carla_get_current_parameter_value(CarlaHostHandle handle,uint pluginId,uint32_t parameterId)1932 float carla_get_current_parameter_value(CarlaHostHandle handle, uint pluginId, uint32_t parameterId)
1933 {
1934     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0.0f);
1935 
1936     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1937     {
1938         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(), 0.0f);
1939 
1940         return plugin->getParameterValue(parameterId);
1941     }
1942 
1943     return 0.0f;
1944 }
1945 
carla_get_internal_parameter_value(CarlaHostHandle handle,uint pluginId,int32_t parameterId)1946 float carla_get_internal_parameter_value(CarlaHostHandle handle, uint pluginId, int32_t parameterId)
1947 {
1948 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1949     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, (parameterId == CB::PARAMETER_CTRL_CHANNEL) ? -1.0f : 0.0f);
1950 #else
1951     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0.0f);
1952 #endif
1953     CARLA_SAFE_ASSERT_RETURN(parameterId != CB::PARAMETER_NULL && parameterId > CB::PARAMETER_MAX, 0.0f);
1954 
1955     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1956         return plugin->getInternalParameterValue(parameterId);
1957 
1958     return 0.0f;
1959 }
1960 
1961 // --------------------------------------------------------------------------------------------------------------------
1962 
carla_get_plugin_latency(CarlaHostHandle handle,uint pluginId)1963 uint32_t carla_get_plugin_latency(CarlaHostHandle handle, uint pluginId)
1964 {
1965     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
1966 
1967     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
1968          return plugin->getLatencyInFrames();
1969 
1970     return 0;
1971 }
1972 
1973 // --------------------------------------------------------------------------------------------------------------------
1974 
carla_get_peak_values(CarlaHostHandle handle,uint pluginId)1975 const float* carla_get_peak_values(CarlaHostHandle handle, uint pluginId)
1976 {
1977     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, nullptr);
1978 
1979     return handle->engine->getPeaks(pluginId);
1980 }
1981 
carla_get_input_peak_value(CarlaHostHandle handle,uint pluginId,bool isLeft)1982 float carla_get_input_peak_value(CarlaHostHandle handle, uint pluginId, bool isLeft)
1983 {
1984     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0.0f);
1985 
1986     return handle->engine->getInputPeak(pluginId, isLeft);
1987 }
1988 
carla_get_output_peak_value(CarlaHostHandle handle,uint pluginId,bool isLeft)1989 float carla_get_output_peak_value(CarlaHostHandle handle, uint pluginId, bool isLeft)
1990 {
1991     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0.0f);
1992 
1993     return handle->engine->getOutputPeak(pluginId, isLeft);
1994 }
1995 
1996 // --------------------------------------------------------------------------------------------------------------------
1997 
1998 CARLA_BACKEND_START_NAMESPACE
1999 
2000 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2001 // defined in CarlaPluginInternal.cpp
2002 const void* carla_render_inline_display_internal(const CarlaPluginPtr& plugin, uint32_t width, uint32_t height);
2003 #endif
2004 
2005 // defined in CarlaPluginLV2.cpp
2006 const void* carla_render_inline_display_lv2(const CarlaPluginPtr& plugin, uint32_t width, uint32_t height);
2007 
2008 CARLA_BACKEND_END_NAMESPACE
2009 
carla_render_inline_display(CarlaHostHandle handle,uint pluginId,uint32_t width,uint32_t height)2010 const CarlaInlineDisplayImageSurface* carla_render_inline_display(CarlaHostHandle handle,
2011                                                                   uint pluginId,
2012                                                                   uint32_t width, uint32_t height)
2013 {
2014     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(), nullptr);
2015 
2016     if (handle->engine->isAboutToClose())
2017         return nullptr;
2018 
2019     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2020     {
2021         switch (plugin->getType())
2022         {
2023 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2024         case CB::PLUGIN_INTERNAL:
2025             return (const CarlaInlineDisplayImageSurface*)CB::carla_render_inline_display_internal(plugin, width, height);
2026 #endif
2027         case CB::PLUGIN_LV2:
2028             return (const CarlaInlineDisplayImageSurface*)CB::carla_render_inline_display_lv2(plugin, width, height);
2029         default:
2030             return nullptr;
2031         }
2032     }
2033 
2034     return nullptr;
2035 }
2036 
2037 // --------------------------------------------------------------------------------------------------------------------
2038 
carla_set_active(CarlaHostHandle handle,uint pluginId,bool onOff)2039 void carla_set_active(CarlaHostHandle handle, uint pluginId, bool onOff)
2040 {
2041     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2042 
2043     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2044         plugin->setActive(onOff, true, false);
2045 }
2046 
2047 #ifndef BUILD_BRIDGE
carla_set_drywet(CarlaHostHandle handle,uint pluginId,float value)2048 void carla_set_drywet(CarlaHostHandle handle, uint pluginId, float value)
2049 {
2050     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2051 
2052     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2053         plugin->setDryWet(value, true, false);
2054 }
2055 
carla_set_volume(CarlaHostHandle handle,uint pluginId,float value)2056 void carla_set_volume(CarlaHostHandle handle, uint pluginId, float value)
2057 {
2058     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2059 
2060     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2061         plugin->setVolume(value, true, false);
2062 }
2063 
carla_set_balance_left(CarlaHostHandle handle,uint pluginId,float value)2064 void carla_set_balance_left(CarlaHostHandle handle, uint pluginId, float value)
2065 {
2066     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2067 
2068     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2069         plugin->setBalanceLeft(value, true, false);
2070 }
2071 
carla_set_balance_right(CarlaHostHandle handle,uint pluginId,float value)2072 void carla_set_balance_right(CarlaHostHandle handle, uint pluginId, float value)
2073 {
2074     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2075 
2076     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2077         plugin->setBalanceRight(value, true, false);
2078 }
2079 
carla_set_panning(CarlaHostHandle handle,uint pluginId,float value)2080 void carla_set_panning(CarlaHostHandle handle, uint pluginId, float value)
2081 {
2082     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2083 
2084     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2085         plugin->setPanning(value, true, false);
2086 }
2087 
carla_set_ctrl_channel(CarlaHostHandle handle,uint pluginId,int8_t channel)2088 void carla_set_ctrl_channel(CarlaHostHandle handle, uint pluginId, int8_t channel)
2089 {
2090     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2091     CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,);
2092 
2093     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2094         plugin->setCtrlChannel(channel, true, false);
2095 }
2096 #endif
2097 
carla_set_option(CarlaHostHandle handle,uint pluginId,uint option,bool yesNo)2098 void carla_set_option(CarlaHostHandle handle, uint pluginId, uint option, bool yesNo)
2099 {
2100     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2101 
2102     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2103         plugin->setOption(option, yesNo, false);
2104 }
2105 
2106 // --------------------------------------------------------------------------------------------------------------------
2107 
carla_set_parameter_value(CarlaHostHandle handle,uint pluginId,uint32_t parameterId,float value)2108 void carla_set_parameter_value(CarlaHostHandle handle, uint pluginId, uint32_t parameterId, float value)
2109 {
2110     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2111 
2112     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2113     {
2114         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(),);
2115 
2116         plugin->setParameterValue(parameterId, value, true, true, false);
2117     }
2118 }
2119 
2120 #ifndef BUILD_BRIDGE
2121 
carla_set_parameter_midi_channel(CarlaHostHandle handle,uint pluginId,uint32_t parameterId,uint8_t channel)2122 void carla_set_parameter_midi_channel(CarlaHostHandle handle, uint pluginId, uint32_t parameterId, uint8_t channel)
2123 {
2124     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2125     CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2126 
2127     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2128     {
2129         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(),);
2130 
2131         plugin->setParameterMidiChannel(parameterId, channel, true, false);
2132     }
2133 }
2134 
carla_set_parameter_mapped_control_index(CarlaHostHandle handle,uint pluginId,uint32_t parameterId,int16_t index)2135 void carla_set_parameter_mapped_control_index(CarlaHostHandle handle, uint pluginId, uint32_t parameterId, int16_t index)
2136 {
2137     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2138     CARLA_SAFE_ASSERT_RETURN(index >= CB::CONTROL_INDEX_NONE && index <= CB::CONTROL_INDEX_MAX_ALLOWED,);
2139 
2140     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2141     {
2142         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(),);
2143 
2144         plugin->setParameterMappedControlIndex(parameterId, index, true, false, true);
2145     }
2146 }
2147 
carla_set_parameter_mapped_range(CarlaHostHandle handle,uint pluginId,uint32_t parameterId,float minimum,float maximum)2148 void carla_set_parameter_mapped_range(CarlaHostHandle handle, uint pluginId, uint32_t parameterId, float minimum, float maximum)
2149 {
2150     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2151 
2152     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2153     {
2154         CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(),);
2155 
2156         plugin->setParameterMappedRange(parameterId, minimum, maximum, true, false);
2157     }
2158 }
2159 
carla_set_parameter_touch(CarlaHostHandle handle,uint pluginId,uint32_t parameterId,bool touch)2160 void carla_set_parameter_touch(CarlaHostHandle handle, uint pluginId, uint32_t parameterId, bool touch)
2161 {
2162     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2163 
2164     carla_debug("carla_set_parameter_touch(%p, %i, %i, %s)", handle, pluginId, parameterId, bool2str(touch));
2165     return handle->engine->touchPluginParameter(pluginId, parameterId, touch);
2166 }
2167 #endif
2168 
2169 // --------------------------------------------------------------------------------------------------------------------
2170 
carla_set_program(CarlaHostHandle handle,uint pluginId,uint32_t programId)2171 void carla_set_program(CarlaHostHandle handle, uint pluginId, uint32_t programId)
2172 {
2173     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2174 
2175     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2176     {
2177         CARLA_SAFE_ASSERT_RETURN(programId < plugin->getProgramCount(),);
2178 
2179         plugin->setProgram(static_cast<int32_t>(programId), true, true, false);
2180     }
2181 }
2182 
carla_set_midi_program(CarlaHostHandle handle,uint pluginId,uint32_t midiProgramId)2183 void carla_set_midi_program(CarlaHostHandle handle, uint pluginId, uint32_t midiProgramId)
2184 {
2185     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2186 
2187     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2188     {
2189         CARLA_SAFE_ASSERT_RETURN(midiProgramId < plugin->getMidiProgramCount(),);
2190 
2191         plugin->setMidiProgram(static_cast<int32_t>(midiProgramId), true, true, false);
2192     }
2193 }
2194 
2195 // --------------------------------------------------------------------------------------------------------------------
2196 
carla_set_custom_data(CarlaHostHandle handle,uint pluginId,const char * type,const char * key,const char * value)2197 void carla_set_custom_data(CarlaHostHandle handle, uint pluginId, const char* type, const char* key, const char* value)
2198 {
2199     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2200     CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
2201     CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
2202     CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
2203 
2204     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2205         plugin->setCustomData(type, key, value, true);
2206 }
2207 
carla_set_chunk_data(CarlaHostHandle handle,uint pluginId,const char * chunkData)2208 void carla_set_chunk_data(CarlaHostHandle handle, uint pluginId, const char* chunkData)
2209 {
2210     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2211     CARLA_SAFE_ASSERT_RETURN(chunkData != nullptr && chunkData[0] != '\0',);
2212 
2213     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2214     {
2215         CARLA_SAFE_ASSERT_RETURN(plugin->getOptionsEnabled() & CB::PLUGIN_OPTION_USE_CHUNKS,);
2216 
2217         std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkData));
2218 #ifdef CARLA_PROPER_CPP11_SUPPORT
2219         plugin->setChunkData(chunk.data(), chunk.size());
2220 #else
2221         plugin->setChunkData(&chunk.front(), chunk.size());
2222 #endif
2223     }
2224 }
2225 
2226 // --------------------------------------------------------------------------------------------------------------------
2227 
carla_prepare_for_save(CarlaHostHandle handle,uint pluginId)2228 void carla_prepare_for_save(CarlaHostHandle handle, uint pluginId)
2229 {
2230     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2231 
2232     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2233         plugin->prepareForSave(false);
2234 }
2235 
carla_reset_parameters(CarlaHostHandle handle,uint pluginId)2236 void carla_reset_parameters(CarlaHostHandle handle, uint pluginId)
2237 {
2238     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2239 
2240     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2241         plugin->resetParameters();
2242 }
2243 
carla_randomize_parameters(CarlaHostHandle handle,uint pluginId)2244 void carla_randomize_parameters(CarlaHostHandle handle, uint pluginId)
2245 {
2246     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2247 
2248     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2249         plugin->randomizeParameters();
2250 }
2251 
2252 #ifndef BUILD_BRIDGE
carla_send_midi_note(CarlaHostHandle handle,uint pluginId,uint8_t channel,uint8_t note,uint8_t velocity)2253 void carla_send_midi_note(CarlaHostHandle handle, uint pluginId, uint8_t channel, uint8_t note, uint8_t velocity)
2254 {
2255     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->engine->isRunning(),);
2256 
2257     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2258         plugin->sendMidiSingleNote(channel, note, velocity, true, true, false);
2259 }
2260 #endif
2261 
carla_set_custom_ui_title(CarlaHostHandle handle,uint pluginId,const char * title)2262 void carla_set_custom_ui_title(CarlaHostHandle handle, uint pluginId, const char* title)
2263 {
2264     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2265     CARLA_SAFE_ASSERT_RETURN(title != nullptr,);
2266 
2267     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2268         plugin->setCustomUITitle(title);
2269 }
2270 
carla_show_custom_ui(CarlaHostHandle handle,uint pluginId,bool yesNo)2271 void carla_show_custom_ui(CarlaHostHandle handle, uint pluginId, bool yesNo)
2272 {
2273     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,);
2274 
2275     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2276         plugin->showCustomUI(yesNo);
2277 }
2278 
carla_embed_custom_ui(CarlaHostHandle handle,uint pluginId,void * ptr)2279 void* carla_embed_custom_ui(CarlaHostHandle handle, uint pluginId, void* ptr)
2280 {
2281     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, nullptr);
2282 
2283     if (const CarlaPluginPtr plugin = handle->engine->getPlugin(pluginId))
2284         return plugin->embedCustomUI(ptr);
2285 
2286     return nullptr;
2287 }
2288 
2289 // --------------------------------------------------------------------------------------------------------------------
2290 
carla_get_buffer_size(CarlaHostHandle handle)2291 uint32_t carla_get_buffer_size(CarlaHostHandle handle)
2292 {
2293     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0);
2294 
2295     carla_debug("carla_get_buffer_size(%p)", handle);
2296     return handle->engine->getBufferSize();
2297 }
2298 
carla_get_sample_rate(CarlaHostHandle handle)2299 double carla_get_sample_rate(CarlaHostHandle handle)
2300 {
2301     CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, 0.0);
2302 
2303     carla_debug("carla_get_sample_rate(%p)", handle);
2304     return handle->engine->getSampleRate();
2305 }
2306 
2307 // --------------------------------------------------------------------------------------------------------------------
2308 
carla_get_last_error(CarlaHostHandle handle)2309 const char* carla_get_last_error(CarlaHostHandle handle)
2310 {
2311     carla_debug("carla_get_last_error(%p)", handle);
2312 
2313     if (handle->engine != nullptr)
2314         return handle->engine->getLastError();
2315 
2316     return handle->isStandalone
2317            ? ((CarlaHostStandalone*)handle)->lastError.buffer()
2318            : gNullCharPtr;
2319 }
2320 
carla_get_host_osc_url_tcp(CarlaHostHandle handle)2321 const char* carla_get_host_osc_url_tcp(CarlaHostHandle handle)
2322 {
2323     carla_debug("carla_get_host_osc_url_tcp(%p)", handle);
2324 
2325 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
2326     if (handle->engine == nullptr)
2327     {
2328         carla_stderr2("carla_get_host_osc_url_tcp() failed, engine is not running");
2329         if (handle->isStandalone)
2330             ((CarlaHostStandalone*)handle)->lastError = "Engine is not running";
2331         return gNullCharPtr;
2332     }
2333 
2334     const char* const path = handle->engine->getOscServerPathTCP();
2335 
2336     if (path != nullptr && path[0] != '\0')
2337         return path;
2338 
2339     static const char* const notAvailable = "(OSC TCP port not available)";
2340     return notAvailable;
2341 #else
2342     return "(OSC support not available in this build)";
2343 
2344     // unused
2345     (void)handle;
2346 #endif
2347 }
2348 
carla_get_host_osc_url_udp(CarlaHostHandle handle)2349 const char* carla_get_host_osc_url_udp(CarlaHostHandle handle)
2350 {
2351     carla_debug("carla_get_host_osc_url_udp(%p)", handle);
2352 
2353 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
2354     if (handle->engine == nullptr)
2355     {
2356         carla_stderr2("carla_get_host_osc_url_udp() failed, engine is not running");
2357         if (handle->isStandalone)
2358             ((CarlaHostStandalone*)handle)->lastError = "Engine is not running";
2359         return gNullCharPtr;
2360     }
2361 
2362     const char* const path = handle->engine->getOscServerPathUDP();
2363 
2364     if (path != nullptr && path[0] != '\0')
2365         return path;
2366 
2367     static const char* const notAvailable = "(OSC UDP port not available)";
2368     return notAvailable;
2369 #else
2370     return "(OSC support not available in this build)";
2371 
2372     // unused
2373     (void)handle;
2374 #endif
2375 }
2376 
2377 // --------------------------------------------------------------------------------------------------------------------
2378 
2379 #ifndef CARLA_PLUGIN_EXPORT
2380 # define CARLA_PLUGIN_UI_CLASS_PREFIX Standalone
2381 # include "CarlaPluginUI.cpp"
2382 # undef CARLA_PLUGIN_UI_CLASS_PREFIX
2383 # include "CarlaDssiUtils.cpp"
2384 # include "CarlaMacUtils.cpp"
2385 # include "CarlaPatchbayUtils.cpp"
2386 # include "CarlaPipeUtils.cpp"
2387 # include "CarlaProcessUtils.cpp"
2388 # include "CarlaStateUtils.cpp"
2389 # include "utils/Information.cpp"
2390 # include "utils/Windows.cpp"
2391 #endif /* CARLA_PLUGIN_EXPORT */
2392 
2393 // --------------------------------------------------------------------------------------------------------------------
2394