1 /*
2  * Carla Plugin
3  * Copyright (C) 2011-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_PLUGIN_INTERNAL_HPP_INCLUDED
19 #define CARLA_PLUGIN_INTERNAL_HPP_INCLUDED
20 
21 #include "CarlaPlugin.hpp"
22 
23 #include "CarlaJuceUtils.hpp"
24 #include "CarlaLibUtils.hpp"
25 #include "CarlaStateUtils.hpp"
26 
27 #include "CarlaMIDI.h"
28 #include "CarlaMutex.hpp"
29 #include "CarlaString.hpp"
30 #include "RtLinkedList.hpp"
31 
32 CARLA_BACKEND_START_NAMESPACE
33 
34 // -----------------------------------------------------------------------
35 // Engine helper macro, sets lastError and returns false/NULL
36 
37 #define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err)  if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return false;   }
38 #define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return nullptr; }
39 
40 #define CARLA_SAFE_EXCEPTION_RETURN_ERR(excptMsg, errMsg)  catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return false;   }
41 #define CARLA_SAFE_EXCEPTION_RETURN_ERRN(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return nullptr; }
42 
43 // -----------------------------------------------------------------------
44 // Maximum pre-allocated events for some plugin types
45 
46 const ushort kPluginMaxMidiEvents = 512;
47 
48 // -----------------------------------------------------------------------
49 // Extra parameter hints, hidden from backend
50 
51 const uint PARAMETER_MAPPED_RANGES_SET = 0x10000;
52 const uint PARAMETER_IS_STRICT_BOUNDS  = 0x20000;
53 const uint PARAMETER_IS_TRIGGER        = 0x40000;
54 
55 // -----------------------------------------------------------------------
56 // Extra plugin hints, hidden from backend
57 
58 const uint PLUGIN_EXTRA_HINT_HAS_MIDI_IN  = 0x01;
59 const uint PLUGIN_EXTRA_HINT_HAS_MIDI_OUT = 0x02;
60 
61 // -----------------------------------------------------------------------
62 // Special parameters
63 
64 enum SpecialParameterType {
65     PARAMETER_SPECIAL_NULL        = 0,
66     PARAMETER_SPECIAL_FREEWHEEL   = 1,
67     PARAMETER_SPECIAL_LATENCY     = 2,
68     PARAMETER_SPECIAL_SAMPLE_RATE = 3,
69     PARAMETER_SPECIAL_TIME        = 4
70 };
71 
72 // -----------------------------------------------------------------------
73 
74 /*!
75  * Post-RT event type.
76  * These are events postponned from within the process function,
77  *
78  * During process, we cannot lock, allocate memory or do UI stuff.
79  * Events have to be postponned to be executed later, on a separate thread.
80  * @see PluginPostRtEvent
81  */
82 enum PluginPostRtEventType {
83     kPluginPostRtEventNull = 0,
84     kPluginPostRtEventParameterChange,
85     kPluginPostRtEventProgramChange,
86     kPluginPostRtEventMidiProgramChange,
87     kPluginPostRtEventNoteOn,
88     kPluginPostRtEventNoteOff,
89     kPluginPostRtEventMidiLearn
90 };
91 
92 /*!
93  * A Post-RT event.
94  * @see PluginPostRtEventType
95  */
96 struct PluginPostRtEvent {
97     PluginPostRtEventType type;
98     bool sendCallback;
99     union {
100         struct {
101             int32_t index;
102             float value;
103         } parameter;
104         struct {
105             uint32_t index;
106         } program;
107         struct {
108             uint8_t channel;
109             uint8_t note;
110             uint8_t velocity;
111         } note;
112         struct {
113             uint32_t parameter;
114             uint8_t cc;
115             uint8_t channel;
116         } midiLearn;
117     };
118 };
119 
120 // -----------------------------------------------------------------------
121 
122 struct ExternalMidiNote {
123     int8_t  channel; // invalid if -1
124     uint8_t note;    // 0 to 127
125     uint8_t velo;    // 1 to 127, 0 for note-off
126 };
127 
128 // -----------------------------------------------------------------------
129 
130 struct PluginAudioPort {
131     uint32_t rindex;
132     CarlaEngineAudioPort* port;
133 };
134 
135 struct PluginAudioData {
136     uint32_t count;
137     PluginAudioPort* ports;
138 
139     PluginAudioData() noexcept;
140     ~PluginAudioData() noexcept;
141     void createNew(uint32_t newCount);
142     void clear() noexcept;
143     void initBuffers() const noexcept;
144 
145     CARLA_DECLARE_NON_COPY_STRUCT(PluginAudioData)
146 };
147 
148 // -----------------------------------------------------------------------
149 
150 struct PluginCVPort {
151     uint32_t rindex;
152     //uint32_t param; // FIXME is this needed?
153     CarlaEngineCVPort* port;
154 };
155 
156 struct PluginCVData {
157     uint32_t count;
158     PluginCVPort* ports;
159 
160     PluginCVData() noexcept;
161     ~PluginCVData() noexcept;
162     void createNew(uint32_t newCount);
163     void clear() noexcept;
164     void initBuffers() const noexcept;
165 
166     CARLA_DECLARE_NON_COPY_STRUCT(PluginCVData)
167 };
168 
169 // -----------------------------------------------------------------------
170 
171 struct PluginEventData {
172     CarlaEngineEventPort* portIn;
173     CarlaEngineEventPort* portOut;
174 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
175     CarlaEngineCVSourcePorts* cvSourcePorts;
176 #endif
177 
178     PluginEventData() noexcept;
179     ~PluginEventData() noexcept;
180     void clear() noexcept;
181     void initBuffers() const noexcept;
182 
183     CARLA_DECLARE_NON_COPY_STRUCT(PluginEventData)
184 };
185 
186 // -----------------------------------------------------------------------
187 
188 struct PluginParameterData {
189     uint32_t count;
190     ParameterData* data;
191     ParameterRanges* ranges;
192     SpecialParameterType* special;
193 
194     PluginParameterData() noexcept;
195     ~PluginParameterData() noexcept;
196     void createNew(uint32_t newCount, bool withSpecial);
197     void clear() noexcept;
198     float getFixedValue(uint32_t parameterId, float value) const noexcept;
199     float getFinalUnnormalizedValue(uint32_t parameterId, float normalizedValue) const noexcept;
200     float getFinalValueWithMidiDelta(uint32_t parameterId, float value, int8_t delta) const noexcept;
201 
202     CARLA_DECLARE_NON_COPY_STRUCT(PluginParameterData)
203 };
204 
205 // -----------------------------------------------------------------------
206 
207 typedef const char* ProgramName;
208 
209 struct PluginProgramData {
210     uint32_t count;
211     int32_t current;
212     ProgramName* names;
213 
214     PluginProgramData() noexcept;
215     ~PluginProgramData() noexcept;
216     void createNew(uint32_t newCount);
217     void clear() noexcept;
218 
219     CARLA_DECLARE_NON_COPY_STRUCT(PluginProgramData)
220 };
221 
222 // -----------------------------------------------------------------------
223 
224 struct PluginMidiProgramData {
225     uint32_t count;
226     int32_t current;
227     MidiProgramData* data;
228 
229     PluginMidiProgramData() noexcept;
230     ~PluginMidiProgramData() noexcept;
231     void createNew(uint32_t newCount);
232     void clear() noexcept;
233     const MidiProgramData& getCurrent() const noexcept;
234 
235     CARLA_DECLARE_NON_COPY_STRUCT(PluginMidiProgramData)
236 };
237 
238 // -----------------------------------------------------------------------
239 
240 struct CarlaPlugin::ProtectedData {
241     CarlaEngine* const engine;
242     CarlaEngineClient* client;
243 
244     uint id;
245     uint hints;
246     uint options;
247     uint32_t nodeId;
248 
249     bool active;
250     bool enabled;
251     bool needsReset;
252 
253     bool engineBridged;
254     bool enginePlugin;
255 
256     lib_t lib;
257     lib_t uiLib;
258 
259     // misc
260     int8_t ctrlChannel;
261     uint   extraHints;
262 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
263     int32_t midiLearnParameterIndex;
264     uint    transientTryCounter;
265     bool    transientFirstTry;
266 #endif
267 
268     // data 1
269     const char* name;
270     const char* filename;
271     const char* iconName;
272 
273     // data 2
274     PluginAudioData audioIn;
275     PluginAudioData audioOut;
276     PluginCVData cvIn;
277     PluginCVData cvOut;
278     PluginEventData event;
279     PluginParameterData param;
280     PluginProgramData prog;
281     PluginMidiProgramData midiprog;
282     LinkedList<CustomData> custom;
283 
284     CarlaMutex masterMutex; // global master lock
285     CarlaMutex singleMutex; // small lock used only in processSingle()
286 
287     CarlaStateSave stateSave;
288 
289     CarlaString uiTitle;
290 
291     struct ExternalNotes {
292         CarlaMutex mutex;
293         RtLinkedList<ExternalMidiNote>::Pool dataPool;
294         RtLinkedList<ExternalMidiNote> data;
295 
296         ExternalNotes() noexcept;
297         ~ExternalNotes() noexcept;
298         void appendNonRT(const ExternalMidiNote& note) noexcept;
299         void clear() noexcept;
300 
301         CARLA_DECLARE_NON_COPY_STRUCT(ExternalNotes)
302 
303     } extNotes;
304 
305     struct Latency {
306         uint32_t frames;
307 #ifndef BUILD_BRIDGE
308         uint32_t channels;
309         float**  buffers;
310 #endif
311 
312         Latency() noexcept;
313 #ifndef BUILD_BRIDGE
314         ~Latency() noexcept;
315         void clearBuffers() noexcept;
316         void recreateBuffers(uint32_t newChannels, uint32_t newFrames);
317 #endif
318 
319         CARLA_DECLARE_NON_COPY_STRUCT(Latency)
320 
321     } latency;
322 
323     class PostRtEvents {
324     public:
325         PostRtEvents() noexcept;
326         ~PostRtEvents() noexcept;
327         void appendRT(const PluginPostRtEvent& event) noexcept;
328         void trySplice() noexcept;
329 
330         struct Access {
AccessCarlaPlugin::ProtectedData::PostRtEvents::Access331             Access(PostRtEvents& e)
332               : data2(e.dataPool),
333                 poolMutex(e.poolMutex)
334             {
335                 const CarlaMutexLocker cml1(e.dataMutex);
336                 const CarlaMutexLocker cml2(e.poolMutex);
337 
338                 if (e.data.isNotEmpty())
339                     e.data.moveTo(data2, true);
340             }
341 
~AccessCarlaPlugin::ProtectedData::PostRtEvents::Access342             ~Access()
343             {
344                 const CarlaMutexLocker cml(poolMutex);
345 
346                 data2.clear();
347             }
348 
getDataIteratorCarlaPlugin::ProtectedData::PostRtEvents::Access349             inline RtLinkedList<PluginPostRtEvent>::Itenerator getDataIterator() const noexcept
350             {
351                 return data2.begin2();
352             }
353 
isEmptyCarlaPlugin::ProtectedData::PostRtEvents::Access354             inline std::size_t isEmpty() const noexcept
355             {
356                 return data2.isEmpty();
357             }
358 
359         private:
360             RtLinkedList<PluginPostRtEvent> data2;
361             CarlaMutex& poolMutex;
362         };
363 
364     private:
365         RtLinkedList<PluginPostRtEvent>::Pool dataPool;
366         RtLinkedList<PluginPostRtEvent> data, dataPendingRT;
367         CarlaMutex dataMutex;
368         CarlaMutex dataPendingMutex;
369         CarlaMutex poolMutex;
370 
371         CARLA_DECLARE_NON_COPY_CLASS(PostRtEvents)
372 
373     } postRtEvents;
374 
375     struct PostUiEvents {
376         CarlaMutex mutex;
377         LinkedList<PluginPostRtEvent> data;
378 
379         PostUiEvents() noexcept;
380         ~PostUiEvents() noexcept;
381         void append(const PluginPostRtEvent& event) noexcept;
382         void clear() noexcept;
383 
384         CARLA_DECLARE_NON_COPY_STRUCT(PostUiEvents)
385 
386     } postUiEvents;
387 
388 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
389     struct PostProc {
390         float dryWet;
391         float volume;
392         float balanceLeft;
393         float balanceRight;
394         float panning;
395 
396         PostProc() noexcept;
397 
398         CARLA_DECLARE_NON_COPY_STRUCT(PostProc)
399 
400     } postProc;
401 #endif
402 
403     ProtectedData(CarlaEngine* engine, uint idx) noexcept;
404     ~ProtectedData() noexcept;
405 
406     // -------------------------------------------------------------------
407     // Buffer functions
408 
409     void clearBuffers() noexcept;
410 
411     // -------------------------------------------------------------------
412     // Post-poned events
413 
414     void postponeRtEvent(const PluginPostRtEvent& rtEvent) noexcept;
415     void postponeParameterChangeRtEvent(bool sendCallbackLater, int32_t index, float value) noexcept;
416     void postponeProgramChangeRtEvent(bool sendCallbackLater, uint32_t index) noexcept;
417     void postponeMidiProgramChangeRtEvent(bool sendCallbackLater, uint32_t index) noexcept;
418     void postponeNoteOnRtEvent(bool sendCallbackLater, uint8_t channel, uint8_t note, uint8_t velocity) noexcept;
419     void postponeNoteOffRtEvent(bool sendCallbackLater, uint8_t channel, uint8_t note) noexcept;
420     void postponeMidiLearnRtEvent(bool sendCallbackLater, uint32_t parameter, uint8_t cc, uint8_t channel) noexcept;
421 
422     // -------------------------------------------------------------------
423     // Library functions
424 
425     static const char* libError(const char* filename) noexcept;
426 
427     bool libOpen(const char* filename) noexcept;
428     bool libClose() noexcept;
429     void setCanDeleteLib(bool canDelete) noexcept;
430 
431     bool uiLibOpen(const char* filename, bool canDelete) noexcept;
432     bool uiLibClose() noexcept;
433 
434     template<typename Func>
libSymbolCarlaPlugin::ProtectedData435     Func libSymbol(const char* symbol) const noexcept
436     {
437         return lib_symbol<Func>(lib, symbol);
438     }
439 
440     template<typename Func>
uiLibSymbolCarlaPlugin::ProtectedData441     Func uiLibSymbol(const char* symbol) const noexcept
442     {
443         return lib_symbol<Func>(uiLib, symbol);
444     }
445 
446     // -------------------------------------------------------------------
447     // Misc
448 
449 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
450     void tryTransient() noexcept;
451 #endif
452     void updateParameterValues(CarlaPlugin* plugin,
453                                bool sendCallback, bool sendOsc, bool useDefault) noexcept;
454     void updateDefaultParameterValues(CarlaPlugin* plugin) noexcept;
455 
456     // -------------------------------------------------------------------
457 
458 #ifdef CARLA_PROPER_CPP11_SUPPORT
459     ProtectedData() = delete;
460     CARLA_DECLARE_NON_COPY_STRUCT(ProtectedData);
461 #endif
462     CARLA_LEAK_DETECTOR(ProtectedData);
463 };
464 
465 CARLA_BACKEND_END_NAMESPACE
466 
467 #endif // CARLA_PLUGIN_INTERNAL_HPP_INCLUDED
468