DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
8.5KB

  1. /*
  2. * Native Bridge for DPF
  3. * Copyright (C) 2021-2022 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. #ifndef NATIVE_BRIDGE_HPP_INCLUDED
  17. #define NATIVE_BRIDGE_HPP_INCLUDED
  18. #include "JackBridge.hpp"
  19. #include "../../extra/RingBuffer.hpp"
  20. using DISTRHO_NAMESPACE::HeapRingBuffer;
  21. struct NativeBridge {
  22. // Current status information
  23. uint bufferSize;
  24. uint sampleRate;
  25. // Port caching information
  26. uint numAudioIns;
  27. uint numAudioOuts;
  28. uint numMidiIns;
  29. uint numMidiOuts;
  30. // JACK callbacks
  31. JackProcessCallback jackProcessCallback = nullptr;
  32. JackBufferSizeCallback bufferSizeCallback = nullptr;
  33. void* jackProcessArg = nullptr;
  34. void* jackBufferSizeArg = nullptr;
  35. // Runtime buffers
  36. enum PortMask {
  37. kPortMaskAudio = 0x1000,
  38. kPortMaskMIDI = 0x2000,
  39. kPortMaskInput = 0x4000,
  40. kPortMaskOutput = 0x8000,
  41. kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI,
  42. kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI,
  43. };
  44. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  45. float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS];
  46. float* audioBufferStorage;
  47. #endif
  48. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  49. static constexpr const uint32_t kMaxMIDIInputMessageSize = 3;
  50. uint8_t midiDataStorage[kMaxMIDIInputMessageSize];
  51. HeapRingBuffer midiInBufferCurrent;
  52. HeapRingBuffer midiInBufferPending;
  53. #endif
  54. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  55. HeapRingBuffer midiOutBuffer;
  56. #endif
  57. NativeBridge()
  58. : bufferSize(0),
  59. sampleRate(0),
  60. numAudioIns(0),
  61. numAudioOuts(0),
  62. numMidiIns(0),
  63. numMidiOuts(0),
  64. jackProcessCallback(nullptr),
  65. bufferSizeCallback(nullptr),
  66. jackProcessArg(nullptr),
  67. jackBufferSizeArg(nullptr)
  68. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  69. , audioBuffers()
  70. , audioBufferStorage(nullptr)
  71. #endif
  72. {
  73. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  74. std::memset(audioBuffers, 0, sizeof(audioBuffers));
  75. #endif
  76. }
  77. virtual ~NativeBridge() {}
  78. virtual bool open(const char* const clientName) = 0;
  79. virtual bool close() = 0;
  80. virtual bool activate() = 0;
  81. virtual bool deactivate() = 0;
  82. virtual bool supportsAudioInput() const
  83. {
  84. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  85. return true;
  86. #else
  87. return false;
  88. #endif
  89. }
  90. virtual bool isAudioInputEnabled() const
  91. {
  92. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  93. return true;
  94. #else
  95. return false;
  96. #endif
  97. }
  98. virtual bool supportsBufferSizeChanges() const { return false; }
  99. virtual bool supportsMIDI() const { return false; }
  100. virtual bool isMIDIEnabled() const { return false; }
  101. virtual bool requestAudioInput() { return false; }
  102. virtual bool requestBufferSizeChange(uint32_t) { return false; }
  103. virtual bool requestMIDI() { return false; }
  104. uint32_t getBufferSize() const noexcept
  105. {
  106. return bufferSize;
  107. }
  108. uint32_t getEventCount()
  109. {
  110. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  111. // NOTE: this function is only called once per run
  112. midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending);
  113. return midiInBufferCurrent.getReadableDataSize() / (kMaxMIDIInputMessageSize + 1u);
  114. #else
  115. return 0;
  116. #endif
  117. }
  118. bool getEvent(jack_midi_event_t* const event)
  119. {
  120. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  121. // NOTE: this function is called for all events in index succession
  122. if (midiInBufferCurrent.getReadableDataSize() >= (kMaxMIDIInputMessageSize + 1u))
  123. {
  124. event->time = 0; // TODO
  125. event->size = midiInBufferCurrent.readByte();
  126. event->buffer = midiDataStorage;
  127. return midiInBufferCurrent.readCustomData(midiDataStorage, kMaxMIDIInputMessageSize);
  128. }
  129. #endif
  130. return false;
  131. // maybe unused
  132. (void)event;
  133. }
  134. void clearEventBuffer()
  135. {
  136. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  137. midiOutBuffer.clearData();
  138. #endif
  139. }
  140. bool writeEvent(const jack_nframes_t time, const jack_midi_data_t* const data, const uint32_t size)
  141. {
  142. if (size > 3)
  143. return false;
  144. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  145. if (midiOutBuffer.writeByte(size) && midiOutBuffer.writeCustomData(data, size))
  146. {
  147. bool fail = false;
  148. // align
  149. switch (size)
  150. {
  151. case 1: fail |= !midiOutBuffer.writeByte(0);
  152. // fall-through
  153. case 2: fail |= !midiOutBuffer.writeByte(0);
  154. }
  155. fail |= !midiOutBuffer.writeUInt(time);
  156. midiOutBuffer.commitWrite();
  157. return !fail;
  158. }
  159. midiOutBuffer.commitWrite();
  160. #endif
  161. return false;
  162. // maybe unused
  163. (void)data;
  164. (void)time;
  165. }
  166. void allocBuffers()
  167. {
  168. DISTRHO_SAFE_ASSERT_RETURN(bufferSize != 0,);
  169. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  170. audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)];
  171. for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  172. audioBuffers[i] = audioBufferStorage + (bufferSize * i);
  173. #endif
  174. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  175. std::memset(audioBufferStorage, 0, sizeof(float)*bufferSize*DISTRHO_PLUGIN_NUM_INPUTS);
  176. #endif
  177. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  178. midiInBufferCurrent.createBuffer(kMaxMIDIInputMessageSize * 512);
  179. midiInBufferPending.createBuffer(kMaxMIDIInputMessageSize * 512);
  180. #endif
  181. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  182. midiOutBuffer.createBuffer(2048);
  183. #endif
  184. }
  185. void freeBuffers()
  186. {
  187. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  188. delete[] audioBufferStorage;
  189. audioBufferStorage = nullptr;
  190. #endif
  191. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  192. midiInBufferCurrent.deleteBuffer();
  193. midiInBufferPending.deleteBuffer();
  194. #endif
  195. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  196. midiOutBuffer.deleteBuffer();
  197. #endif
  198. }
  199. jack_port_t* registerPort(const char* const type, const ulong flags)
  200. {
  201. bool isAudio, isInput;
  202. /**/ if (std::strcmp(type, JACK_DEFAULT_AUDIO_TYPE) == 0)
  203. isAudio = true;
  204. else if (std::strcmp(type, JACK_DEFAULT_MIDI_TYPE) == 0)
  205. isAudio = false;
  206. else
  207. return nullptr;
  208. /**/ if (flags & JackPortIsInput)
  209. isInput = true;
  210. else if (flags & JackPortIsOutput)
  211. isInput = false;
  212. else
  213. return nullptr;
  214. const uintptr_t ret = (isAudio ? kPortMaskAudio : kPortMaskMIDI)
  215. | (isInput ? kPortMaskInput : kPortMaskOutput);
  216. return (jack_port_t*)(ret + (isAudio ? (isInput ? numAudioIns++ : numAudioOuts++)
  217. : (isInput ? numMidiIns++ : numMidiOuts++)));
  218. }
  219. void* getPortBuffer(jack_port_t* const port)
  220. {
  221. const uintptr_t portMask = (uintptr_t)port;
  222. DISTRHO_SAFE_ASSERT_RETURN(portMask != 0x0, nullptr);
  223. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  224. if (portMask & kPortMaskAudio)
  225. return audioBuffers[(portMask & kPortMaskInput ? 0 : DISTRHO_PLUGIN_NUM_INPUTS) + (portMask & 0x0fff)];
  226. #endif
  227. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  228. if ((portMask & kPortMaskInputMIDI) == kPortMaskInputMIDI)
  229. return (void*)0x1;
  230. #endif
  231. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  232. if ((portMask & kPortMaskOutputMIDI) == kPortMaskOutputMIDI)
  233. return (void*)0x2;
  234. #endif
  235. return nullptr;
  236. }
  237. };
  238. #endif // NATIVE_BRIDGE_HPP_INCLUDED