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
33 #include "lv2/atom-util.h"
35 CARLA_BRIDGE_UI_START_NAMESPACE
37 // ---------------------------------------------------------------------
39 CarlaBridgeFormat::CarlaBridgeFormat() noexcept
47 fBase64ReservedChunk()
49 carla_debug("CarlaBridgeFormat::CarlaBridgeFormat()");
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();
69 if (fToolkit
!= nullptr)
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
);
117 if (fLastMsgTimer
> 0)
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());
137 const LV2_Atom
* const atom((const LV2_Atom
*)&fBase64ReservedChunk
.front());
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
);
149 if (std::strcmp(msg
, "urid") == 0)
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);
159 dspURIDReceived(urid
, uri
);
164 if (std::strcmp(msg
, "control") == 0)
169 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index
), true);
170 CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value
), true);
172 dspParameterChanged(index
, value
);
176 if (std::strcmp(msg
, "parameter") == 0)
181 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(uri
, true), true);
182 CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value
), true);
184 dspParameterChanged(uri
, value
);
188 if (std::strcmp(msg
, "program") == 0)
192 CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(index
), true);
194 dspProgramChanged(index
);
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
);
209 if (std::strcmp(msg
, "configure") == 0)
214 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(key
, true), true);
215 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value
, false), true);
217 dspStateChanged(key
, value
);
223 if (std::strcmp(msg
, "note") == 0)
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
);
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;
256 uiOptionsChanged(opts
);
258 delete[] opts
.windowTitle
;
262 CARLA_SAFE_ASSERT_RETURN(fToolkit
!= nullptr, true);
264 if (std::strcmp(msg
, "show") == 0)
271 if (std::strcmp(msg
, "focus") == 0)
277 if (std::strcmp(msg
, "hide") == 0)
283 if (std::strcmp(msg
, "quit") == 0)
285 fQuitReceived
= true;
292 if (std::strcmp(msg
, "uiTitle") == 0)
296 CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(title
, false), true);
298 fToolkit
->setTitle(title
);
302 carla_stderr("CarlaBridgeFormat::msgReceived : %s", msg
);
306 // ---------------------------------------------------------------------
308 bool CarlaBridgeFormat::init(const int argc
, const char* argv
[])
310 CARLA_SAFE_ASSERT_RETURN(fToolkit
!= nullptr, false);
314 if (! initPipeClient(argv
))
319 // wait for ui options
320 for (; ++fLastMsgTimer
< 50 && ! fGotOptions
;)
328 carla_stderr2("CarlaBridgeFormat::init() - did not get options on time, quitting...");
329 writeExitingMessageAndWait();
335 if (! fToolkit
->init(argc
, argv
))
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 // ---------------------------------------------------------------------