comparison DPF-Prymula-audioplugins/dpf/distrho/src/jackbridge/NativeBridge.hpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 /*
2 * Native Bridge for DPF
3 * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #ifndef NATIVE_BRIDGE_HPP_INCLUDED
18 #define NATIVE_BRIDGE_HPP_INCLUDED
19
20 #include "JackBridge.hpp"
21
22 #include "../../extra/RingBuffer.hpp"
23
24 #if DISTRHO_PLUGIN_NUM_INPUTS > 2
25 # define DISTRHO_PLUGIN_NUM_INPUTS_2 2
26 #else
27 # define DISTRHO_PLUGIN_NUM_INPUTS_2 DISTRHO_PLUGIN_NUM_INPUTS
28 #endif
29
30 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 2
31 # define DISTRHO_PLUGIN_NUM_OUTPUTS_2 2
32 #else
33 # define DISTRHO_PLUGIN_NUM_OUTPUTS_2 DISTRHO_PLUGIN_NUM_OUTPUTS
34 #endif
35
36 using DISTRHO_NAMESPACE::HeapRingBuffer;
37
38 struct NativeBridge {
39 // Current status information
40 uint bufferSize;
41 uint sampleRate;
42
43 // Port caching information
44 uint numAudioIns;
45 uint numAudioOuts;
46 uint numCvIns;
47 uint numCvOuts;
48 uint numMidiIns;
49 uint numMidiOuts;
50
51 // JACK callbacks
52 JackProcessCallback jackProcessCallback = nullptr;
53 JackBufferSizeCallback bufferSizeCallback = nullptr;
54 void* jackProcessArg = nullptr;
55 void* jackBufferSizeArg = nullptr;
56
57 // Runtime buffers
58 enum PortMask {
59 kPortMaskAudio = 0x1000,
60 kPortMaskCV = 0x2000,
61 kPortMaskMIDI = 0x4000,
62 kPortMaskInput = 0x10000,
63 kPortMaskOutput = 0x20000,
64 kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI,
65 kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI,
66 };
67 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
68 float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS];
69 float* audioBufferStorage;
70 #endif
71 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
72 bool midiAvailable;
73 #endif
74 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
75 static constexpr const uint32_t kMaxMIDIInputMessageSize = 3;
76 uint8_t midiDataStorage[kMaxMIDIInputMessageSize];
77 HeapRingBuffer midiInBufferCurrent;
78 HeapRingBuffer midiInBufferPending;
79 #endif
80 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
81 HeapRingBuffer midiOutBuffer;
82 #endif
83
84 NativeBridge()
85 : bufferSize(0),
86 sampleRate(0),
87 numAudioIns(0),
88 numAudioOuts(0),
89 numCvIns(0),
90 numCvOuts(0),
91 numMidiIns(0),
92 numMidiOuts(0),
93 jackProcessCallback(nullptr),
94 bufferSizeCallback(nullptr),
95 jackProcessArg(nullptr),
96 jackBufferSizeArg(nullptr)
97 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
98 , audioBuffers()
99 , audioBufferStorage(nullptr)
100 #endif
101 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
102 , midiAvailable(false)
103 #endif
104 {
105 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
106 std::memset(audioBuffers, 0, sizeof(audioBuffers));
107 #endif
108 }
109
110 virtual ~NativeBridge() {}
111 virtual bool open(const char* const clientName) = 0;
112 virtual bool close() = 0;
113 virtual bool activate() = 0;
114 virtual bool deactivate() = 0;
115
116 virtual bool supportsAudioInput() const
117 {
118 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
119 return true;
120 #else
121 return false;
122 #endif
123 }
124
125 virtual bool isAudioInputEnabled() const
126 {
127 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
128 return true;
129 #else
130 return false;
131 #endif
132 }
133
134 virtual bool supportsBufferSizeChanges() const { return false; }
135 virtual bool isMIDIEnabled() const { return false; }
136 virtual bool requestAudioInput() { return false; }
137 virtual bool requestBufferSizeChange(uint32_t) { return false; }
138 virtual bool requestMIDI() { return false; }
139
140 uint32_t getBufferSize() const noexcept
141 {
142 return bufferSize;
143 }
144
145 bool supportsMIDI() const noexcept
146 {
147 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
148 return midiAvailable;
149 #else
150 return false;
151 #endif
152 }
153
154 uint32_t getEventCount()
155 {
156 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
157 if (midiAvailable)
158 {
159 // NOTE: this function is only called once per run
160 midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending);
161 return midiInBufferCurrent.getReadableDataSize() / (kMaxMIDIInputMessageSize + 1u);
162 }
163 #endif
164
165 return 0;
166 }
167
168 bool getEvent(jack_midi_event_t* const event)
169 {
170 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
171 // NOTE: this function is called for all events in index succession
172 if (midiAvailable && midiInBufferCurrent.getReadableDataSize() >= (kMaxMIDIInputMessageSize + 1u))
173 {
174 event->time = 0; // TODO
175 event->size = midiInBufferCurrent.readByte();
176 event->buffer = midiDataStorage;
177 return midiInBufferCurrent.readCustomData(midiDataStorage, kMaxMIDIInputMessageSize);
178 }
179 #endif
180 return false;
181 // maybe unused
182 (void)event;
183 }
184
185 void clearEventBuffer()
186 {
187 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
188 if (midiAvailable)
189 midiOutBuffer.clearData();
190 #endif
191 }
192
193 bool writeEvent(const jack_nframes_t time, const jack_midi_data_t* const data, const uint32_t size)
194 {
195 if (size > 3)
196 return false;
197
198 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
199 if (midiAvailable)
200 {
201 if (midiOutBuffer.writeByte(size) && midiOutBuffer.writeCustomData(data, size))
202 {
203 bool fail = false;
204 // align
205 switch (size)
206 {
207 case 1: fail |= !midiOutBuffer.writeByte(0);
208 // fall-through
209 case 2: fail |= !midiOutBuffer.writeByte(0);
210 }
211 fail |= !midiOutBuffer.writeUInt(time);
212 midiOutBuffer.commitWrite();
213 return !fail;
214 }
215 midiOutBuffer.commitWrite();
216 }
217 #endif
218
219 return false;
220 // maybe unused
221 (void)data;
222 (void)time;
223 }
224
225 void allocBuffers(const bool audio, const bool midi)
226 {
227 DISTRHO_SAFE_ASSERT_RETURN(bufferSize != 0,);
228
229 if (audio)
230 {
231 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
232 audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)];
233
234 for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
235 audioBuffers[i] = audioBufferStorage + (bufferSize * i);
236 #endif
237
238 #if DISTRHO_PLUGIN_NUM_INPUTS > 0
239 std::memset(audioBufferStorage, 0, sizeof(float)*bufferSize*DISTRHO_PLUGIN_NUM_INPUTS);
240 #endif
241 }
242
243 if (midi)
244 {
245 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
246 midiInBufferCurrent.createBuffer(kMaxMIDIInputMessageSize * 512);
247 midiInBufferPending.createBuffer(kMaxMIDIInputMessageSize * 512);
248 #endif
249 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
250 midiOutBuffer.createBuffer(2048);
251 #endif
252 }
253 }
254
255 void freeBuffers()
256 {
257 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
258 delete[] audioBufferStorage;
259 audioBufferStorage = nullptr;
260 #endif
261 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
262 midiInBufferCurrent.deleteBuffer();
263 midiInBufferPending.deleteBuffer();
264 #endif
265 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
266 midiOutBuffer.deleteBuffer();
267 #endif
268 }
269
270 jack_port_t* registerPort(const char* const type, const ulong flags)
271 {
272 uintptr_t ret = 0;
273
274 /**/ if (flags & JackPortIsInput)
275 ret |= kPortMaskInput;
276 else if (flags & JackPortIsOutput)
277 ret |= kPortMaskOutput;
278 else
279 return nullptr;
280
281 /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0)
282 {
283 if (flags & JackPortIsControlVoltage)
284 {
285 ret |= kPortMaskAudio;
286 ret += flags & JackPortIsInput ? numAudioIns++ : numAudioOuts++;
287 }
288 else
289 {
290 ret |= kPortMaskCV;
291 ret += flags & JackPortIsInput ? numCvIns++ : numCvOuts++;
292 }
293 }
294 else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0)
295 {
296 ret |= kPortMaskMIDI;
297 ret += flags & JackPortIsInput ? numMidiIns++ : numMidiOuts++;
298 }
299 else
300 {
301 return nullptr;
302 }
303
304 return (jack_port_t*)ret;
305 }
306
307 void* getPortBuffer(jack_port_t* const port)
308 {
309 const uintptr_t portMask = (uintptr_t)port;
310 DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr);
311
312 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
313 if (portMask & (kPortMaskAudio|kPortMaskCV))
314 return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)];
315 #endif
316 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
317 if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI)
318 return (void*)0x1;
319 #endif
320 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
321 if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI)
322 return (void*)0x2;
323 #endif
324
325 return nullptr;
326 }
327 };
328
329 #endif // NATIVE_BRIDGE_HPP_INCLUDED