Update CI version
[carla.git] / source / bridges-ui / CarlaBridgeFormat.cpp
blob2703fa2899076ee8d2805fdc69843561b11d348f
1 /*
2 * Carla Bridge UI
3 * Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
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.
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.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaBridgeFormat.hpp"
19 #include "CarlaBridgeToolkit.hpp"
21 #include "CarlaBase64Utils.hpp"
22 #include "CarlaProcessUtils.hpp"
23 #include "CarlaTimeUtils.hpp"
25 #include "CarlaMIDI.h"
27 // needed for atom-util
28 #ifndef nullptr
29 # undef NULL
30 # define NULL nullptr
31 #endif
33 #include "lv2/atom-util.h"
35 CARLA_BRIDGE_UI_START_NAMESPACE
37 // ---------------------------------------------------------------------
39 CarlaBridgeFormat::CarlaBridgeFormat() noexcept
40 : CarlaPipeClient(),
41 fQuitReceived(false),
42 fGotOptions(false),
43 fLastMsgTimer(-1),
44 fToolkit(nullptr),
45 fLib(nullptr),
46 fLibFilename(),
47 fBase64ReservedChunk()
49 carla_debug("CarlaBridgeFormat::CarlaBridgeFormat()");
51 try {
52 fToolkit = CarlaBridgeToolkit::createNew(this);
53 } CARLA_SAFE_EXCEPTION_RETURN("CarlaBridgeToolkit::createNew",);
56 CarlaBridgeFormat::~CarlaBridgeFormat() /*noexcept*/
58 carla_debug("CarlaBridgeFormat::~CarlaBridgeFormat()");
60 if (isPipeRunning() && ! fQuitReceived)
61 writeExitingMessageAndWait();
63 if (fLib != nullptr)
65 lib_close(fLib);
66 fLib = nullptr;
69 if (fToolkit != nullptr)
71 fToolkit->quit();
72 delete fToolkit;
73 fToolkit = nullptr;
76 closePipeClient();
79 // ---------------------------------------------------------------------
81 bool CarlaBridgeFormat::libOpen(const char* const filename) noexcept
83 CARLA_SAFE_ASSERT_RETURN(fLib == nullptr, false);
85 fLib = lib_open(filename);
86 fLibFilename = filename;
88 return fLib != nullptr;
91 void* CarlaBridgeFormat::libSymbol(const char* const symbol) const noexcept
93 CARLA_SAFE_ASSERT_RETURN(fLib != nullptr, nullptr);
95 return lib_symbol<void*>(fLib, symbol);
98 const char* CarlaBridgeFormat::libError() const noexcept
100 CARLA_SAFE_ASSERT_RETURN(fLibFilename.isNotEmpty(), nullptr);
102 return lib_error(fLibFilename);
105 // ---------------------------------------------------------------------
107 bool CarlaBridgeFormat::msgReceived(const char* const msg) noexcept
109 carla_debug("CarlaBridgeFormat::msgReceived(\"%s\")", msg);
111 if (! fGotOptions && std::strcmp(msg, "urid") != 0 && std::strcmp(msg, "uiOptions") != 0)
113 carla_stderr2("CarlaBridgeFormat::msgReceived(\"%s\") - invalid message while waiting for options", msg);
114 return true;
117 if (fLastMsgTimer > 0)
118 --fLastMsgTimer;
120 if (std::strcmp(msg, "atom") == 0)
122 uint32_t index, atomTotalSize, base64Size;
123 const char* base64atom;
125 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true);
126 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(atomTotalSize), true);
127 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(base64Size), true);
128 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false, base64Size), true);
130 carla_getChunkFromBase64String_impl(fBase64ReservedChunk, base64atom);
131 CARLA_SAFE_ASSERT_UINT2_RETURN(fBase64ReservedChunk.size() >= sizeof(LV2_Atom),
132 fBase64ReservedChunk.size(), sizeof(LV2_Atom), true);
134 #ifdef CARLA_PROPER_CPP11_SUPPORT
135 const LV2_Atom* const atom((const LV2_Atom*)fBase64ReservedChunk.data());
136 #else
137 const LV2_Atom* const atom((const LV2_Atom*)&fBase64ReservedChunk.front());
138 #endif
139 const uint32_t atomTotalSizeCheck(lv2_atom_total_size(atom));
141 CARLA_SAFE_ASSERT_UINT2_RETURN(atomTotalSizeCheck == atomTotalSize, atomTotalSizeCheck, atomTotalSize, true);
142 CARLA_SAFE_ASSERT_UINT2_RETURN(atomTotalSizeCheck == fBase64ReservedChunk.size(),
143 atomTotalSizeCheck, fBase64ReservedChunk.size(), true);
145 dspAtomReceived(index, atom);
146 return true;
149 if (std::strcmp(msg, "urid") == 0)
151 uint32_t urid, size;
152 const char* uri;
154 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(urid), true);
155 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(size), true);
156 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, false, size), true);
158 if (urid != 0)
159 dspURIDReceived(urid, uri);
161 return true;
164 if (std::strcmp(msg, "control") == 0)
166 uint32_t index;
167 float value;
169 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true);
170 CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true);
172 dspParameterChanged(index, value);
173 return true;
176 if (std::strcmp(msg, "parameter") == 0)
178 const char* uri;
179 float value;
181 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri, true), true);
182 CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true);
184 dspParameterChanged(uri, value);
185 return true;
188 if (std::strcmp(msg, "program") == 0)
190 uint32_t index;
192 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index), true);
194 dspProgramChanged(index);
195 return true;
198 if (std::strcmp(msg, "midiprogram") == 0)
200 uint32_t bank, program;
202 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(bank), true);
203 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(program), true);
205 dspMidiProgramChanged(bank, program);
206 return true;
209 if (std::strcmp(msg, "configure") == 0)
211 const char* key;
212 const char* value;
214 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(key, true), true);
215 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value, false), true);
217 dspStateChanged(key, value);
219 delete[] key;
220 return true;
223 if (std::strcmp(msg, "note") == 0)
225 bool onOff;
226 uint8_t channel, note, velocity;
228 CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(onOff), true);
229 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(channel), true);
230 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(note), true);
231 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(velocity), true);
233 dspNoteReceived(onOff, channel, note, velocity);
234 return true;
237 if (std::strcmp(msg, "uiOptions") == 0)
239 BridgeFormatOptions opts;
240 uint64_t transientWindowId;
242 CARLA_SAFE_ASSERT_RETURN(readNextLineAsDouble(opts.sampleRate), true);
243 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(opts.bgColor), true);
244 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(opts.fgColor), true);
245 CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(opts.uiScale), true);
246 CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(opts.useTheme), true);
247 CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(opts.useThemeColors), true);
248 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(opts.windowTitle, true), true);
249 CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(transientWindowId), true);
250 opts.transientWindowId = transientWindowId;
252 // we can assume we are not standalone if we got options from controller side
253 opts.isStandalone = false;
255 fGotOptions = true;
256 uiOptionsChanged(opts);
258 delete[] opts.windowTitle;
259 return true;
262 CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, true);
264 if (std::strcmp(msg, "show") == 0)
266 fToolkit->show();
267 fToolkit->focus();
268 return true;
271 if (std::strcmp(msg, "focus") == 0)
273 fToolkit->focus();
274 return true;
277 if (std::strcmp(msg, "hide") == 0)
279 fToolkit->hide();
280 return true;
283 if (std::strcmp(msg, "quit") == 0)
285 fQuitReceived = true;
286 fToolkit->quit();
287 delete fToolkit;
288 fToolkit = nullptr;
289 return true;
292 if (std::strcmp(msg, "uiTitle") == 0)
294 const char* title;
296 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(title, false), true);
298 fToolkit->setTitle(title);
299 return true;
302 carla_stderr("CarlaBridgeFormat::msgReceived : %s", msg);
303 return false;
306 // ---------------------------------------------------------------------
308 bool CarlaBridgeFormat::init(const int argc, const char* argv[])
310 CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, false);
312 if (argc == 7)
314 if (! initPipeClient(argv))
315 return false;
317 fLastMsgTimer = 0;
319 // wait for ui options
320 for (; ++fLastMsgTimer < 50 && ! fGotOptions;)
322 idlePipe(true);
323 carla_msleep(20);
326 if (! fGotOptions)
328 carla_stderr2("CarlaBridgeFormat::init() - did not get options on time, quitting...");
329 writeExitingMessageAndWait();
330 closePipeClient();
331 return false;
335 if (! fToolkit->init(argc, argv))
337 if (argc == 7)
338 closePipeClient();
339 return false;
342 return true;
345 void CarlaBridgeFormat::exec(const bool showUI)
347 CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr,);
349 carla_terminateProcessOnParentExit(true);
350 fToolkit->exec(showUI);
353 // ---------------------------------------------------------------------
355 CARLA_BRIDGE_UI_END_NAMESPACE
357 #include "CarlaPipeUtils.cpp"
359 // ---------------------------------------------------------------------