Mercurial > hg > pub > prymula > com
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 |