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