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.

395 lines
13KB

  1. /*
  2. * DISTRHO Ildaeil Plugin
  3. * Copyright (C) 2021 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 LICENSE file.
  16. */
  17. #include "CarlaNativePlugin.h"
  18. #include "DistrhoPlugin.hpp"
  19. START_NAMESPACE_DISTRHO
  20. // -----------------------------------------------------------------------------------------------------------
  21. using namespace CarlaBackend;
  22. static uint32_t host_get_buffer_size(NativeHostHandle);
  23. static double host_get_sample_rate(NativeHostHandle);
  24. static bool host_is_offline(NativeHostHandle);
  25. static const NativeTimeInfo* host_get_time_info(NativeHostHandle handle);
  26. static bool host_write_midi_event(NativeHostHandle handle, const NativeMidiEvent* event);
  27. static intptr_t host_dispatcher(NativeHostHandle handle, NativeHostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt);
  28. // -----------------------------------------------------------------------------------------------------------
  29. class IldaeilPlugin : public Plugin
  30. {
  31. public:
  32. const NativePluginDescriptor* fCarlaPluginDescriptor;
  33. NativePluginHandle fCarlaPluginHandle;
  34. NativeHostDescriptor fCarlaHostDescriptor;
  35. CarlaHostHandle fCarlaHostHandle;
  36. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  37. static constexpr const uint kMaxMidiEventCount = 512;
  38. NativeMidiEvent* fMidiEvents;
  39. uint32_t fMidiEventCount;
  40. float* fDummyBuffer;
  41. float* fDummyBuffers[2];
  42. #endif
  43. mutable NativeTimeInfo fCarlaTimeInfo;
  44. void* fUI;
  45. IldaeilPlugin()
  46. : Plugin(0, 0, 0),
  47. fCarlaPluginDescriptor(nullptr),
  48. fCarlaPluginHandle(nullptr),
  49. fCarlaHostHandle(nullptr),
  50. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  51. fMidiEvents(nullptr),
  52. fMidiEventCount(0),
  53. fDummyBuffer(nullptr),
  54. #endif
  55. fUI(nullptr)
  56. {
  57. fCarlaPluginDescriptor = carla_get_native_rack_plugin();
  58. DISTRHO_SAFE_ASSERT_RETURN(fCarlaPluginDescriptor != nullptr,);
  59. memset(&fCarlaHostDescriptor, 0, sizeof(fCarlaHostDescriptor));
  60. memset(&fCarlaTimeInfo, 0, sizeof(fCarlaTimeInfo));
  61. fCarlaHostDescriptor.handle = this;
  62. fCarlaHostDescriptor.resourceDir = carla_get_library_folder();
  63. fCarlaHostDescriptor.uiName = "Ildaeil";
  64. fCarlaHostDescriptor.uiParentId = 0;
  65. fCarlaHostDescriptor.get_buffer_size = host_get_buffer_size;
  66. fCarlaHostDescriptor.get_sample_rate = host_get_sample_rate;
  67. fCarlaHostDescriptor.is_offline = host_is_offline;
  68. fCarlaHostDescriptor.get_time_info = host_get_time_info;
  69. fCarlaHostDescriptor.write_midi_event = host_write_midi_event;
  70. fCarlaHostDescriptor.ui_parameter_changed = nullptr;
  71. fCarlaHostDescriptor.ui_midi_program_changed = nullptr;
  72. fCarlaHostDescriptor.ui_custom_data_changed = nullptr;
  73. fCarlaHostDescriptor.ui_closed = nullptr;
  74. fCarlaHostDescriptor.ui_open_file = nullptr;
  75. fCarlaHostDescriptor.ui_save_file = nullptr;
  76. fCarlaHostDescriptor.dispatcher = host_dispatcher;
  77. fCarlaPluginHandle = fCarlaPluginDescriptor->instantiate(&fCarlaHostDescriptor);
  78. DISTRHO_SAFE_ASSERT_RETURN(fCarlaPluginHandle != nullptr,);
  79. fCarlaHostHandle = carla_create_native_plugin_host_handle(fCarlaPluginDescriptor, fCarlaPluginHandle);
  80. DISTRHO_SAFE_ASSERT_RETURN(fCarlaHostHandle != nullptr,);
  81. carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_BINARIES, 0, "/usr/lib/carla");
  82. carla_set_engine_option(fCarlaHostHandle, ENGINE_OPTION_PATH_RESOURCES, 0, "/usr/share/carla/resources");
  83. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  84. fMidiEvents = new NativeMidiEvent[kMaxMidiEventCount];
  85. fDummyBuffer = new float[getBufferSize()];
  86. fDummyBuffers[0] = fDummyBuffer;
  87. fDummyBuffers[1] = fDummyBuffer;
  88. #endif
  89. }
  90. ~IldaeilPlugin() override
  91. {
  92. if (fCarlaHostHandle != nullptr)
  93. {
  94. carla_host_handle_free(fCarlaHostHandle);
  95. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  96. delete[] fMidiEvents;
  97. delete[] fDummyBuffer;
  98. #endif
  99. }
  100. if (fCarlaPluginHandle != nullptr)
  101. fCarlaPluginDescriptor->cleanup(fCarlaPluginHandle);
  102. }
  103. const NativeTimeInfo* hostGetTimeInfo() const noexcept
  104. {
  105. const TimePosition& timePos(getTimePosition());
  106. fCarlaTimeInfo.playing = timePos.playing;
  107. fCarlaTimeInfo.frame = timePos.frame;
  108. fCarlaTimeInfo.bbt.valid = timePos.bbt.valid;
  109. fCarlaTimeInfo.bbt.bar = timePos.bbt.bar;
  110. fCarlaTimeInfo.bbt.beat = timePos.bbt.beat;
  111. fCarlaTimeInfo.bbt.tick = timePos.bbt.tick;
  112. fCarlaTimeInfo.bbt.barStartTick = timePos.bbt.barStartTick;
  113. fCarlaTimeInfo.bbt.beatsPerBar = timePos.bbt.beatsPerBar;
  114. fCarlaTimeInfo.bbt.beatType = timePos.bbt.beatType;
  115. fCarlaTimeInfo.bbt.ticksPerBeat = timePos.bbt.ticksPerBeat;
  116. fCarlaTimeInfo.bbt.beatsPerMinute = timePos.bbt.beatsPerMinute;
  117. return &fCarlaTimeInfo;
  118. }
  119. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  120. bool hostWriteMidiEvent(const NativeMidiEvent* const event)
  121. {
  122. MidiEvent midiEvent;
  123. midiEvent.frame = event->time;
  124. midiEvent.size = event->size;
  125. midiEvent.dataExt = nullptr;
  126. uint32_t i = 0;
  127. for (; i < event->size; ++i)
  128. midiEvent.data[i] = event->data[i];
  129. for (; i < MidiEvent::kDataSize; ++i)
  130. midiEvent.data[i] = 0;
  131. return writeMidiEvent(midiEvent);
  132. }
  133. #endif
  134. void hostResizeUI(const uint width, const uint height)
  135. {
  136. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  137. d_stdout("asking to resizing ui to %u %u - I SAY NO", width, height);
  138. // fUI->setSize(width, height);
  139. }
  140. protected:
  141. /* --------------------------------------------------------------------------------------------------------
  142. * Information */
  143. /**
  144. Get the plugin label.
  145. A plugin label follows the same rules as Parameter::symbol, with the exception that it can start with numbers.
  146. */
  147. const char* getLabel() const override
  148. {
  149. #if DISTRHO_PLUGIN_IS_SYNTH
  150. return "IldaeilSynth";
  151. #elif DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  152. return "IldaeilMIDI";
  153. #else
  154. return "IldaeilFX";
  155. #endif
  156. }
  157. /**
  158. Get an extensive comment/description about the plugin.
  159. */
  160. const char* getDescription() const override
  161. {
  162. return "Ildaeil is a mini-plugin host working as a plugin, allowing one-to-one plugin format reusage.";
  163. }
  164. /**
  165. Get the plugin author/maker.
  166. */
  167. const char* getMaker() const override
  168. {
  169. return "DISTRHO";
  170. }
  171. /**
  172. Get the plugin homepage.
  173. */
  174. const char* getHomePage() const override
  175. {
  176. return "https://github.com/DISTRHO/Ildaeil";
  177. }
  178. /**
  179. Get the plugin license name (a single line of text).
  180. For commercial plugins this should return some short copyright information.
  181. */
  182. const char* getLicense() const override
  183. {
  184. return "GPLv2+";
  185. }
  186. /**
  187. Get the plugin version, in hexadecimal.
  188. */
  189. uint32_t getVersion() const override
  190. {
  191. return d_version(1, 0, 0);
  192. }
  193. /**
  194. Get the plugin unique Id.
  195. This value is used by LADSPA, DSSI and VST plugin formats.
  196. */
  197. int64_t getUniqueId() const override
  198. {
  199. #if DISTRHO_PLUGIN_IS_SYNTH
  200. return d_cconst('d', 'I', 'l', 'S');
  201. #elif DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  202. return d_cconst('d', 'I', 'l', 'M');
  203. #else
  204. return d_cconst('d', 'I', 'l', 'F');
  205. #endif
  206. }
  207. /* --------------------------------------------------------------------------------------------------------
  208. * Init */
  209. /* --------------------------------------------------------------------------------------------------------
  210. * Internal data */
  211. /* --------------------------------------------------------------------------------------------------------
  212. * Process */
  213. void activate() override
  214. {
  215. if (fCarlaPluginHandle != nullptr)
  216. fCarlaPluginDescriptor->activate(fCarlaPluginHandle);
  217. }
  218. void deactivate() override
  219. {
  220. if (fCarlaPluginHandle != nullptr)
  221. fCarlaPluginDescriptor->deactivate(fCarlaPluginHandle);
  222. }
  223. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  224. void run(const float** inputs, float** outputs, uint32_t frames,
  225. const MidiEvent* dpfMidiEvents, uint32_t dpfMidiEventCount) override
  226. #else
  227. void run(const float** inputs, float** outputs, uint32_t frames) override
  228. #endif
  229. {
  230. if (fCarlaPluginHandle != nullptr)
  231. {
  232. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  233. uint32_t midiEventCount = 0;
  234. for (uint32_t i=0; i < dpfMidiEventCount; ++i)
  235. {
  236. const MidiEvent& dpfMidiEvent(dpfMidiEvents[i]);
  237. if (dpfMidiEvent.size > 4)
  238. continue;
  239. NativeMidiEvent& midiEvent(fMidiEvents[midiEventCount]);
  240. midiEvent.time = dpfMidiEvent.frame;
  241. midiEvent.port = 0;
  242. midiEvent.size = dpfMidiEvent.size;
  243. std::memcpy(midiEvent.data, dpfMidiEvent.data, midiEvent.size);
  244. if (++midiEventCount == kMaxMidiEventCount)
  245. break;
  246. }
  247. # if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  248. fCarlaPluginDescriptor->process(fCarlaPluginHandle, fDummyBuffers, fDummyBuffers, frames,
  249. fMidiEvents, midiEventCount);
  250. // unused
  251. (void)outputs;
  252. # else
  253. fCarlaPluginDescriptor->process(fCarlaPluginHandle, fDummyBuffers, outputs, frames,
  254. fMidiEvents, midiEventCount);
  255. # endif
  256. // unused
  257. (void)inputs;
  258. #else
  259. fCarlaPluginDescriptor->process(fCarlaPluginHandle, (float**)inputs, outputs, frames, nullptr, 0);
  260. #endif
  261. }
  262. else
  263. {
  264. std::memset(outputs[0], 0, sizeof(float)*frames);
  265. std::memset(outputs[1], 0, sizeof(float)*frames);
  266. }
  267. }
  268. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  269. void bufferSizeChanged(const uint32_t newBufferSize) override
  270. {
  271. delete[] fDummyBuffer;
  272. fDummyBuffer = new float[newBufferSize];
  273. fDummyBuffers[0] = fDummyBuffer;
  274. fDummyBuffers[1] = fDummyBuffer;
  275. }
  276. #endif
  277. // -------------------------------------------------------------------------------------------------------
  278. /**
  279. Set our plugin class as non-copyable and add a leak detector just in case.
  280. */
  281. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(IldaeilPlugin)
  282. };
  283. // -----------------------------------------------------------------------------------------------------------
  284. static uint32_t host_get_buffer_size(const NativeHostHandle handle)
  285. {
  286. return static_cast<IldaeilPlugin*>(handle)->getBufferSize();
  287. }
  288. static double host_get_sample_rate(const NativeHostHandle handle)
  289. {
  290. return static_cast<IldaeilPlugin*>(handle)->getSampleRate();
  291. }
  292. static bool host_is_offline(NativeHostHandle)
  293. {
  294. return false;
  295. }
  296. static const NativeTimeInfo* host_get_time_info(const NativeHostHandle handle)
  297. {
  298. return static_cast<IldaeilPlugin*>(handle)->hostGetTimeInfo();
  299. }
  300. static bool host_write_midi_event(const NativeHostHandle handle, const NativeMidiEvent* const event)
  301. {
  302. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  303. return static_cast<IldaeilPlugin*>(handle)->hostWriteMidiEvent(event);
  304. #else
  305. return handle != nullptr && event != nullptr && false;
  306. #endif
  307. }
  308. static intptr_t host_dispatcher(const NativeHostHandle handle, const NativeHostDispatcherOpcode opcode,
  309. const int32_t index, const intptr_t value, void* const ptr, const float opt)
  310. {
  311. switch (opcode)
  312. {
  313. case NATIVE_HOST_OPCODE_UI_RESIZE:
  314. static_cast<IldaeilPlugin*>(handle)->hostResizeUI(index, value);
  315. break;
  316. default:
  317. break;
  318. }
  319. return 0;
  320. // unused
  321. (void)ptr;
  322. (void)opt;
  323. }
  324. /* ------------------------------------------------------------------------------------------------------------
  325. * Plugin entry point, called by DPF to create a new plugin instance. */
  326. Plugin* createPlugin()
  327. {
  328. return new IldaeilPlugin();
  329. }
  330. // -----------------------------------------------------------------------------------------------------------
  331. END_NAMESPACE_DISTRHO