1 /*
2 * Carla Bridge utils
3 * Copyright (C) 2013-2019 Filipe Coelho <falktx@falktx.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
16 */
17
18 #ifndef CARLA_BRIDGE_UTILS_HPP_INCLUDED
19 #define CARLA_BRIDGE_UTILS_HPP_INCLUDED
20
21 #include "CarlaBridgeDefines.hpp"
22 #include "CarlaMutex.hpp"
23 #include "CarlaRingBuffer.hpp"
24 #include "CarlaString.hpp"
25
26 // -------------------------------------------------------------------------------------------------------------------
27
28 static inline
PluginBridgeRtClientOpcode2str(const PluginBridgeRtClientOpcode opcode)29 const char* PluginBridgeRtClientOpcode2str(const PluginBridgeRtClientOpcode opcode) noexcept
30 {
31 switch (opcode)
32 {
33 case kPluginBridgeRtClientNull:
34 return "kPluginBridgeRtClientNull";
35 case kPluginBridgeRtClientSetAudioPool:
36 return "kPluginBridgeRtClientSetAudioPool";
37 case kPluginBridgeRtClientSetBufferSize:
38 return "kPluginBridgeRtClientSetBufferSize";
39 case kPluginBridgeRtClientSetSampleRate:
40 return "kPluginBridgeRtClientSetSampleRate";
41 case kPluginBridgeRtClientSetOnline:
42 return "kPluginBridgeRtClientSetOnline";
43 case kPluginBridgeRtClientControlEventParameter:
44 return "kPluginBridgeRtClientControlEventParameter";
45 case kPluginBridgeRtClientControlEventMidiBank:
46 return "kPluginBridgeRtClientControlEventMidiBank";
47 case kPluginBridgeRtClientControlEventMidiProgram:
48 return "kPluginBridgeRtClientControlEventMidiProgram";
49 case kPluginBridgeRtClientControlEventAllSoundOff:
50 return "kPluginBridgeRtClientControlEventAllSoundOff";
51 case kPluginBridgeRtClientControlEventAllNotesOff:
52 return "kPluginBridgeRtClientControlEventAllNotesOff";
53 case kPluginBridgeRtClientMidiEvent:
54 return "kPluginBridgeRtClientMidiEvent";
55 case kPluginBridgeRtClientProcess:
56 return "kPluginBridgeRtClientProcess";
57 case kPluginBridgeRtClientQuit:
58 return "kPluginBridgeRtClientQuit";
59 }
60
61 carla_stderr("CarlaBackend::PluginBridgeRtClientOpcode2str(%i) - invalid opcode", opcode);
62 return nullptr;
63 }
64
65 static inline
PluginBridgeNonRtClientOpcode2str(const PluginBridgeNonRtClientOpcode opcode)66 const char* PluginBridgeNonRtClientOpcode2str(const PluginBridgeNonRtClientOpcode opcode) noexcept
67 {
68 switch (opcode)
69 {
70 case kPluginBridgeNonRtClientNull:
71 return "kPluginBridgeNonRtClientNull";
72 case kPluginBridgeNonRtClientVersion:
73 return "kPluginBridgeNonRtClientVersion";
74 case kPluginBridgeNonRtClientPing:
75 return "kPluginBridgeNonRtClientPing";
76 case kPluginBridgeNonRtClientPingOnOff:
77 return "kPluginBridgeNonRtClientPingOnOff";
78 case kPluginBridgeNonRtClientActivate:
79 return "kPluginBridgeNonRtClientActivate";
80 case kPluginBridgeNonRtClientDeactivate:
81 return "kPluginBridgeNonRtClientDeactivate";
82 case kPluginBridgeNonRtClientInitialSetup:
83 return "kPluginBridgeNonRtClientInitialSetup";
84 case kPluginBridgeNonRtClientSetParameterValue:
85 return "kPluginBridgeNonRtClientSetParameterValue";
86 case kPluginBridgeNonRtClientSetParameterMidiChannel:
87 return "kPluginBridgeNonRtClientSetParameterMidiChannel";
88 case kPluginBridgeNonRtClientSetParameterMappedControlIndex:
89 return "kPluginBridgeNonRtClientSetParameterMappedControlIndex";
90 case kPluginBridgeNonRtClientSetProgram:
91 return "kPluginBridgeNonRtClientSetProgram";
92 case kPluginBridgeNonRtClientSetMidiProgram:
93 return "kPluginBridgeNonRtClientSetMidiProgram";
94 case kPluginBridgeNonRtClientSetCustomData:
95 return "kPluginBridgeNonRtClientSetCustomData";
96 case kPluginBridgeNonRtClientSetChunkDataFile:
97 return "kPluginBridgeNonRtClientSetChunkDataFile";
98 case kPluginBridgeNonRtClientSetCtrlChannel:
99 return "kPluginBridgeNonRtClientSetCtrlChannel";
100 case kPluginBridgeNonRtClientSetOption:
101 return "kPluginBridgeNonRtClientSetOption";
102 case kPluginBridgeNonRtClientGetParameterText:
103 return "kPluginBridgeNonRtClientGetParameterText";
104 case kPluginBridgeNonRtClientPrepareForSave:
105 return "kPluginBridgeNonRtClientPrepareForSave";
106 case kPluginBridgeNonRtClientRestoreLV2State:
107 return "kPluginBridgeNonRtClientRestoreLV2State";
108 case kPluginBridgeNonRtClientShowUI:
109 return "kPluginBridgeNonRtClientShowUI";
110 case kPluginBridgeNonRtClientHideUI:
111 return "kPluginBridgeNonRtClientHideUI";
112 case kPluginBridgeNonRtClientUiParameterChange:
113 return "kPluginBridgeNonRtClientUiParameterChange";
114 case kPluginBridgeNonRtClientUiProgramChange:
115 return "kPluginBridgeNonRtClientUiProgramChange";
116 case kPluginBridgeNonRtClientUiMidiProgramChange:
117 return "kPluginBridgeNonRtClientUiMidiProgramChange";
118 case kPluginBridgeNonRtClientUiNoteOn:
119 return "kPluginBridgeNonRtClientUiNoteOn";
120 case kPluginBridgeNonRtClientUiNoteOff:
121 return "kPluginBridgeNonRtClientUiNoteOff";
122 case kPluginBridgeNonRtClientQuit:
123 return "kPluginBridgeNonRtClientQuit";
124 case kPluginBridgeNonRtClientSetParameterMappedRange:
125 return "kPluginBridgeNonRtClientSetParameterMappedRange";
126 case kPluginBridgeNonRtClientSetOptions:
127 return "kPluginBridgeNonRtClientSetOptions";
128 case kPluginBridgeNonRtClientSetWindowTitle:
129 return "kPluginBridgeNonRtClientSetWindowTitle";
130 }
131
132 carla_stderr("CarlaBackend::PluginBridgeNonRtClientOpcode2str(%i) - invalid opcode", opcode);
133 return nullptr;
134 }
135
136 static inline
PluginBridgeNonRtServerOpcode2str(const PluginBridgeNonRtServerOpcode opcode)137 const char* PluginBridgeNonRtServerOpcode2str(const PluginBridgeNonRtServerOpcode opcode) noexcept
138 {
139 switch (opcode)
140 {
141 case kPluginBridgeNonRtServerNull:
142 return "kPluginBridgeNonRtServerNull";
143 case kPluginBridgeNonRtServerPong:
144 return "kPluginBridgeNonRtServerPong";
145 case kPluginBridgeNonRtServerPluginInfo1:
146 return "kPluginBridgeNonRtServerPluginInfo1";
147 case kPluginBridgeNonRtServerPluginInfo2:
148 return "kPluginBridgeNonRtServerPluginInfo2";
149 case kPluginBridgeNonRtServerAudioCount:
150 return "kPluginBridgeNonRtServerAudioCount";
151 case kPluginBridgeNonRtServerMidiCount:
152 return "kPluginBridgeNonRtServerMidiCount";
153 case kPluginBridgeNonRtServerCvCount:
154 return "kPluginBridgeNonRtServerCvCount";
155 case kPluginBridgeNonRtServerParameterCount:
156 return "kPluginBridgeNonRtServerParameterCount";
157 case kPluginBridgeNonRtServerProgramCount:
158 return "kPluginBridgeNonRtServerProgramCount";
159 case kPluginBridgeNonRtServerMidiProgramCount:
160 return "kPluginBridgeNonRtServerMidiProgramCount";
161 case kPluginBridgeNonRtServerPortName:
162 return "kPluginBridgeNonRtServerPortName";
163 case kPluginBridgeNonRtServerParameterData1:
164 return "kPluginBridgeNonRtServerParameterData1";
165 case kPluginBridgeNonRtServerParameterData2:
166 return "kPluginBridgeNonRtServerParameterData2";
167 case kPluginBridgeNonRtServerParameterRanges:
168 return "kPluginBridgeNonRtServerParameterRanges";
169 case kPluginBridgeNonRtServerParameterValue:
170 return "kPluginBridgeNonRtServerParameterValue";
171 case kPluginBridgeNonRtServerParameterValue2:
172 return "kPluginBridgeNonRtServerParameterValue2";
173 case kPluginBridgeNonRtServerParameterTouch:
174 return "kPluginBridgeNonRtServerParameterTouch";
175 case kPluginBridgeNonRtServerDefaultValue:
176 return "kPluginBridgeNonRtServerDefaultValue";
177 case kPluginBridgeNonRtServerCurrentProgram:
178 return "kPluginBridgeNonRtServerCurrentProgram";
179 case kPluginBridgeNonRtServerCurrentMidiProgram:
180 return "kPluginBridgeNonRtServerCurrentMidiProgram";
181 case kPluginBridgeNonRtServerProgramName:
182 return "kPluginBridgeNonRtServerProgramName";
183 case kPluginBridgeNonRtServerMidiProgramData:
184 return "kPluginBridgeNonRtServerMidiProgramData";
185 case kPluginBridgeNonRtServerSetCustomData:
186 return "kPluginBridgeNonRtServerSetCustomData";
187 case kPluginBridgeNonRtServerSetChunkDataFile:
188 return "kPluginBridgeNonRtServerSetChunkDataFile";
189 case kPluginBridgeNonRtServerSetLatency:
190 return "kPluginBridgeNonRtServerSetLatency";
191 case kPluginBridgeNonRtServerSetParameterText:
192 return "kPluginBridgeNonRtServerSetParameterText";
193 case kPluginBridgeNonRtServerReady:
194 return "kPluginBridgeNonRtServerReady";
195 case kPluginBridgeNonRtServerSaved:
196 return "kPluginBridgeNonRtServerSaved";
197 case kPluginBridgeNonRtServerUiClosed:
198 return "kPluginBridgeNonRtServerUiClosed";
199 case kPluginBridgeNonRtServerError:
200 return "kPluginBridgeNonRtServerError";
201 case kPluginBridgeNonRtServerVersion:
202 return "kPluginBridgeNonRtServerVersion";
203 }
204
205 carla_stderr("CarlaBackend::PluginBridgeNonRtServerOpcode2str%i) - invalid opcode", opcode);
206 return nullptr;
207 }
208
209 // -------------------------------------------------------------------------------------------------------------------
210
211 static const std::size_t kBridgeRtClientDataMidiOutSize = 511*4;
212 static const std::size_t kBridgeBaseMidiOutHeaderSize = 6U /* time, port and size */;
213
214 // Server => Client RT
215 struct BridgeRtClientData {
216 BridgeSemaphore sem;
217 BridgeTimeInfo timeInfo;
218 SmallStackBuffer ringBuffer;
219 uint8_t midiOut[kBridgeRtClientDataMidiOutSize];
220 uint32_t procFlags;
221 };
222
223 // Server => Client Non-RT
224 struct BridgeNonRtClientData {
225 BigStackBuffer ringBuffer;
226 };
227
228 // Client => Server Non-RT
229 struct BridgeNonRtServerData {
230 HugeStackBuffer ringBuffer;
231 };
232
233 // -------------------------------------------------------------------------------------------------------------------
234
235 struct BridgeAudioPool {
236 float* data;
237 std::size_t dataSize;
238 CarlaString filename;
239 char shm[64];
240 bool isServer;
241
242 BridgeAudioPool() noexcept;
243 ~BridgeAudioPool() noexcept;
244
245 bool initializeServer() noexcept;
246 bool attachClient(const char* const fname) noexcept;
247 void clear() noexcept;
248
249 void resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept;
250
251 const char* getFilenameSuffix() const noexcept;
252
253 CARLA_DECLARE_NON_COPY_STRUCT(BridgeAudioPool)
254 };
255
256 // -------------------------------------------------------------------------------------------------------------------
257
258 struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> {
259 BridgeRtClientData* data;
260 CarlaString filename;
261 bool needsSemDestroy; // client only
262 char shm[64];
263 bool isServer;
264
265 BridgeRtClientControl() noexcept;
266 ~BridgeRtClientControl() noexcept override;
267
268 bool initializeServer() noexcept;
269 bool attachClient(const char* const basename) noexcept;
270 void clear() noexcept;
271
272 bool mapData() noexcept;
273 void unmapData() noexcept;
274
275 // non-bridge, server
276 bool waitForClient(const uint msecs) noexcept;
277 bool writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept;
278
279 // bridge, client
280 PluginBridgeRtClientOpcode readOpcode() noexcept;
281
282 // helper class that automatically posts semaphore on destructor
283 struct WaitHelper {
284 BridgeRtClientData* const data;
285 const bool ok;
286
287 WaitHelper(BridgeRtClientControl& c) noexcept;
288 ~WaitHelper() noexcept;
289
290 CARLA_DECLARE_NON_COPY_STRUCT(WaitHelper)
291 };
292
293 CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtClientControl)
294 };
295
296 // -------------------------------------------------------------------------------------------------------------------
297
298 struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> {
299 BridgeNonRtClientData* data;
300 CarlaString filename;
301 CarlaMutex mutex;
302 char shm[64];
303 bool isServer;
304
305 BridgeNonRtClientControl() noexcept;
306 ~BridgeNonRtClientControl() noexcept override;
307
308 bool initializeServer() noexcept;
309 bool attachClient(const char* const basename) noexcept;
310 void clear() noexcept;
311
312 bool mapData() noexcept;
313 void unmapData() noexcept;
314
315 // non-bridge, server
316 void waitIfDataIsReachingLimit() noexcept;
317 bool writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept;
318
319 // bridge, client
320 PluginBridgeNonRtClientOpcode readOpcode() noexcept;
321
322 CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtClientControl)
323 };
324
325 // -------------------------------------------------------------------------------------------------------------------
326
327 struct BridgeNonRtServerControl : public CarlaRingBufferControl<HugeStackBuffer> {
328 BridgeNonRtServerData* data;
329 CarlaString filename;
330 CarlaMutex mutex;
331 char shm[64];
332 bool isServer;
333
334 BridgeNonRtServerControl() noexcept;
335 ~BridgeNonRtServerControl() noexcept override;
336
337 bool initializeServer() noexcept;
338 bool attachClient(const char* const basename) noexcept;
339 void clear() noexcept;
340
341 bool mapData() noexcept;
342 void unmapData() noexcept;
343
344 // non-bridge, server
345 PluginBridgeNonRtServerOpcode readOpcode() noexcept;
346
347 // bridge, client
348 void waitIfDataIsReachingLimit() noexcept;
349 bool writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept;
350
351 CARLA_DECLARE_NON_COPY_STRUCT(BridgeNonRtServerControl)
352 };
353
354 // -------------------------------------------------------------------------------------------------------------------
355
356 #endif // CARLA_BRIDGE_UTILS_HPP_INCLUDED
357