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.

1092 lines
42KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 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. #include "DistrhoPluginInternal.hpp"
  17. #include "../extra/ScopedPointer.hpp"
  18. #include "travesty/audio_processor.h"
  19. #include "travesty/component.h"
  20. #include "travesty/edit_controller.h"
  21. #include "travesty/factory.h"
  22. #include <atomic>
  23. #include <vector>
  24. START_NAMESPACE_DISTRHO
  25. // --------------------------------------------------------------------------------------------------------------------
  26. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  27. static const writeMidiFunc writeMidiCallback = nullptr;
  28. #endif
  29. #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  30. static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
  31. #endif
  32. // --------------------------------------------------------------------------------------------------------------------
  33. // custom v3_tuid compatible type
  34. typedef uint32_t dpf_tuid[4];
  35. static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch");
  36. // --------------------------------------------------------------------------------------------------------------------
  37. // custom, constant uids related to DPF
  38. static constexpr const uint32_t dpf_id_entry = d_cconst('D', 'P', 'F', ' ');
  39. static constexpr const uint32_t dpf_id_clas = d_cconst('c', 'l', 'a', 's');
  40. static constexpr const uint32_t dpf_id_comp = d_cconst('c', 'o', 'm', 'p');
  41. static constexpr const uint32_t dpf_id_ctrl = d_cconst('c', 't', 'r', 'l');
  42. static constexpr const uint32_t dpf_id_proc = d_cconst('p', 'r', 'o', 'c');
  43. static constexpr const uint32_t dpf_id_view = d_cconst('v', 'i', 'e', 'w');
  44. // --------------------------------------------------------------------------------------------------------------------
  45. // plugin specific uids (values are filled in during plugin init)
  46. static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, 0 };
  47. static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, 0 };
  48. static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, 0 };
  49. static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, 0 };
  50. static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 };
  51. // --------------------------------------------------------------------------------------------------------------------
  52. // Utility functions
  53. const char* tuid2str(const v3_tuid iid)
  54. {
  55. if (v3_tuid_match(iid, v3_funknown_iid))
  56. return "{v3_funknown}";
  57. if (v3_tuid_match(iid, v3_plugin_base_iid))
  58. return "{v3_plugin_base}";
  59. if (v3_tuid_match(iid, v3_plugin_factory_iid))
  60. return "{v3_plugin_factory}";
  61. if (v3_tuid_match(iid, v3_plugin_factory_2_iid))
  62. return "{v3_plugin_factory_2}";
  63. if (v3_tuid_match(iid, v3_plugin_factory_3_iid))
  64. return "{v3_plugin_factory_3}";
  65. if (v3_tuid_match(iid, v3_component_iid))
  66. return "{v3_component}";
  67. if (v3_tuid_match(iid, v3_bstream_iid))
  68. return "{v3_bstream}";
  69. if (v3_tuid_match(iid, v3_event_list_iid))
  70. return "{v3_event_list}";
  71. if (v3_tuid_match(iid, v3_param_value_queue_iid))
  72. return "{v3_param_value_queue}";
  73. if (v3_tuid_match(iid, v3_param_changes_iid))
  74. return "{v3_param_changes}";
  75. if (v3_tuid_match(iid, v3_process_context_requirements_iid))
  76. return "{v3_process_context_requirements}";
  77. if (v3_tuid_match(iid, v3_audio_processor_iid))
  78. return "{v3_audio_processor}";
  79. if (v3_tuid_match(iid, v3_component_handler_iid))
  80. return "{v3_component_handler}";
  81. if (v3_tuid_match(iid, v3_edit_controller_iid))
  82. return "{v3_edit_controller}";
  83. if (v3_tuid_match(iid, v3_plugin_view_iid))
  84. return "{v3_plugin_view}";
  85. if (v3_tuid_match(iid, v3_plugin_frame_iid))
  86. return "{v3_plugin_frame}";
  87. if (v3_tuid_match(iid, v3_plugin_view_content_scale_steinberg_iid))
  88. return "{v3_plugin_view_content_scale_steinberg}";
  89. if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid))
  90. return "{v3_plugin_view_parameter_finder}";
  91. if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0)
  92. return "{dpf_tuid_class}";
  93. if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0)
  94. return "{dpf_tuid_component}";
  95. if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0)
  96. return "{dpf_tuid_controller}";
  97. if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0)
  98. return "{dpf_tuid_processor}";
  99. if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0)
  100. return "{dpf_tuid_view}";
  101. static char buf[46];
  102. std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}",
  103. (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
  104. (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]),
  105. (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]),
  106. (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15]));
  107. return buf;
  108. }
  109. void strncpy(char* const dst, const char* const src, const size_t size)
  110. {
  111. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  112. if (const size_t len = std::min(std::strlen(src), size-1U))
  113. {
  114. std::memcpy(dst, src, len);
  115. dst[len] = '\0';
  116. }
  117. else
  118. {
  119. dst[0] = '\0';
  120. }
  121. }
  122. void strncpy_16from8(int16_t* const dst, const char* const src, const size_t size)
  123. {
  124. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  125. if (const size_t len = std::min(std::strlen(src), size-1U))
  126. {
  127. for (size_t i=0; i<len; ++i)
  128. {
  129. // skip non-ascii chars
  130. if ((uint8_t)src[i] >= 0x80)
  131. continue;
  132. dst[i] = src[i];
  133. }
  134. dst[len] = 0;
  135. }
  136. else
  137. {
  138. dst[0] = 0;
  139. }
  140. }
  141. // --------------------------------------------------------------------------------------------------------------------
  142. class PluginVst3
  143. {
  144. public:
  145. PluginVst3()
  146. : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback)
  147. {
  148. }
  149. // ----------------------------------------------------------------------------------------------------------------
  150. // stuff for vst3 interfaces
  151. uint32_t getParameterCount() const noexcept
  152. {
  153. return fPlugin.getParameterCount();
  154. }
  155. void getParameterInfo(const uint32_t index, v3_param_info* const info) const noexcept
  156. {
  157. // set up flags
  158. int32_t flags = 0;
  159. const auto desig = fPlugin.getParameterDesignation(index);
  160. const auto hints = fPlugin.getParameterHints(index);
  161. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  162. switch (desig)
  163. {
  164. case kParameterDesignationNull:
  165. break;
  166. case kParameterDesignationBypass:
  167. flags |= V3_PARAM_IS_BYPASS;
  168. break;
  169. }
  170. if (hints & kParameterIsAutomable)
  171. flags |= V3_PARAM_CAN_AUTOMATE;
  172. if (hints & kParameterIsOutput)
  173. flags |= V3_PARAM_READ_ONLY;
  174. // TODO V3_PARAM_IS_LIST
  175. // set up step_count
  176. int32_t step_count = 0;
  177. if (hints & kParameterIsBoolean)
  178. step_count = 1;
  179. if ((hints & kParameterIsInteger) && ranges.max - ranges.min > 1)
  180. step_count = ranges.max - ranges.min - 1;
  181. std::memset(info, 0, sizeof(v3_param_info));
  182. info->param_id = index;
  183. info->flags = flags;
  184. info->step_count = step_count;
  185. info->default_normalised_value = ranges.getNormalizedValue(ranges.def);
  186. // int32_t unit_id;
  187. strncpy_16from8(info->title, fPlugin.getParameterName(index), 128);
  188. strncpy_16from8(info->short_title, fPlugin.getParameterShortName(index), 128);
  189. strncpy_16from8(info->units, fPlugin.getParameterUnit(index), 128);
  190. }
  191. double getNormalizedParameterValue(const uint32_t index)
  192. {
  193. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  194. return ranges.getNormalizedValue(fPlugin.getParameterValue(index));
  195. }
  196. void setNormalizedParameterValue(const uint32_t index, const double value)
  197. {
  198. const uint32_t hints = fPlugin.getParameterHints(index);
  199. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  200. float realValue = ranges.getUnnormalizedValue(value);
  201. if (hints & kParameterIsBoolean)
  202. {
  203. const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f;
  204. realValue = realValue > midRange ? ranges.max : ranges.min;
  205. }
  206. if (hints & kParameterIsInteger)
  207. {
  208. realValue = std::round(realValue);
  209. }
  210. fPlugin.setParameterValue(index, realValue);
  211. }
  212. private:
  213. // Plugin
  214. PluginExporter fPlugin;
  215. // VST3 stuff
  216. // TODO
  217. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  218. bool requestParameterValueChange(uint32_t, float)
  219. {
  220. // TODO
  221. return true;
  222. }
  223. static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
  224. {
  225. return ((PluginVst3*)ptr)->requestParameterValueChange(index, value);
  226. }
  227. #endif
  228. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  229. bool writeMidi(const MidiEvent& midiEvent)
  230. {
  231. // TODO
  232. return true;
  233. }
  234. static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
  235. {
  236. return ((PluginVst3*)ptr)->writeMidi(midiEvent);
  237. }
  238. #endif
  239. };
  240. // --------------------------------------------------------------------------------------------------------------------
  241. // Dummy plugin to get data from
  242. static ScopedPointer<PluginExporter> gPluginInfo;
  243. // --------------------------------------------------------------------------------------------------------------------
  244. // dpf_plugin_view
  245. struct v3_plugin_view_cpp : v3_funknown {
  246. v3_plugin_view view;
  247. };
  248. struct dpf_plugin_view : v3_plugin_view_cpp {
  249. dpf_plugin_view()
  250. {
  251. static const uint8_t* kSupportedFactories[] = {
  252. v3_funknown_iid,
  253. v3_plugin_view_iid
  254. };
  255. // ------------------------------------------------------------------------------------------------------------
  256. // v3_funknown
  257. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  258. {
  259. d_stdout("dpf_plugin_view::query_interface => %s | %p %s %p", __PRETTY_FUNCTION__ + 41, self, tuid2str(iid), iface);
  260. *iface = NULL;
  261. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  262. for (const uint8_t* factory_iid : kSupportedFactories)
  263. {
  264. if (v3_tuid_match(factory_iid, iid))
  265. {
  266. *iface = self;
  267. return V3_OK;
  268. }
  269. }
  270. return V3_NO_INTERFACE;
  271. };
  272. // we only support 1 plugin per binary, so don't have to care here
  273. ref = []V3_API(void* self) -> uint32_t
  274. {
  275. d_stdout("dpf_plugin_view::ref => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  276. return 1;
  277. };
  278. unref = []V3_API(void* self) -> uint32_t
  279. {
  280. d_stdout("dpf_plugin_view::unref => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  281. return 0;
  282. };
  283. // ------------------------------------------------------------------------------------------------------------
  284. // v3_plugin_view
  285. view.is_platform_type_supported = []V3_API(void* self, const char* platform_type) -> v3_result
  286. {
  287. d_stdout("dpf_plugin_view::is_platform_type_supported => %s | %p %s", __PRETTY_FUNCTION__ + 41, self, platform_type);
  288. return V3_OK;
  289. };
  290. view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result
  291. {
  292. d_stdout("dpf_plugin_view::attached => %s | %p %p %s", __PRETTY_FUNCTION__ + 41, self, parent, platform_type);
  293. return V3_OK;
  294. };
  295. view.removed = []V3_API(void* self) -> v3_result
  296. {
  297. d_stdout("dpf_plugin_view::removed => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  298. return V3_OK;
  299. };
  300. view.on_wheel = []V3_API(void* self, float distance) -> v3_result
  301. {
  302. d_stdout("dpf_plugin_view::on_wheel => %s | %p %f", __PRETTY_FUNCTION__ + 41, self, distance);
  303. return V3_OK;
  304. };
  305. view.on_key_down = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result
  306. {
  307. d_stdout("dpf_plugin_view::on_key_down => %s | %p %i %i %i", __PRETTY_FUNCTION__ + 41, self, key_char, key_code, modifiers);
  308. return V3_OK;
  309. };
  310. view.on_key_up = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result
  311. {
  312. d_stdout("dpf_plugin_view::on_key_up => %s | %p %i %i %i", __PRETTY_FUNCTION__ + 41, self, key_char, key_code, modifiers);
  313. return V3_OK;
  314. };
  315. view.get_size = []V3_API(void* self, v3_view_rect*) -> v3_result
  316. {
  317. d_stdout("dpf_plugin_view::get_size => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  318. return V3_OK;
  319. };
  320. view.set_size = []V3_API(void* self, v3_view_rect*) -> v3_result
  321. {
  322. d_stdout("dpf_plugin_view::set_size => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  323. return V3_OK;
  324. };
  325. view.on_focus = []V3_API(void* self, v3_bool state) -> v3_result
  326. {
  327. d_stdout("dpf_plugin_view::on_focus => %s | %p %u", __PRETTY_FUNCTION__ + 41, self, state);
  328. return V3_OK;
  329. };
  330. view.set_frame = []V3_API(void* self, v3_plugin_frame*) -> v3_result
  331. {
  332. d_stdout("dpf_plugin_view::set_frame => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  333. return V3_OK;
  334. };
  335. view.can_resize = []V3_API(void* self) -> v3_result
  336. {
  337. d_stdout("dpf_plugin_view::can_resize => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  338. return V3_OK;
  339. };
  340. view.check_size_constraint = []V3_API(void* self, v3_view_rect*) -> v3_result
  341. {
  342. d_stdout("dpf_plugin_view::check_size_constraint => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  343. return V3_OK;
  344. };
  345. }
  346. };
  347. // --------------------------------------------------------------------------------------------------------------------
  348. // dpf_edit_controller
  349. struct v3_edit_controller_cpp : v3_funknown {
  350. v3_plugin_base base;
  351. v3_edit_controller controller;
  352. };
  353. struct dpf_edit_controller : v3_edit_controller_cpp {
  354. ScopedPointer<PluginVst3>& vst3;
  355. dpf_edit_controller(ScopedPointer<PluginVst3>& v)
  356. : vst3(v)
  357. {
  358. static const uint8_t* kSupportedFactories[] = {
  359. v3_funknown_iid,
  360. v3_edit_controller_iid
  361. };
  362. // ------------------------------------------------------------------------------------------------------------
  363. // v3_funknown
  364. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  365. {
  366. d_stdout("dpf_edit_controller::query_interface => %s | %p %s %p", __PRETTY_FUNCTION__ + 53, self, tuid2str(iid), iface);
  367. *iface = NULL;
  368. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  369. for (const uint8_t* factory_iid : kSupportedFactories)
  370. {
  371. if (v3_tuid_match(factory_iid, iid))
  372. {
  373. *iface = self;
  374. return V3_OK;
  375. }
  376. }
  377. return V3_NO_INTERFACE;
  378. };
  379. // we only support 1 plugin per binary, so don't have to care here
  380. ref = []V3_API(void* self) -> uint32_t
  381. {
  382. d_stdout("dpf_edit_controller::ref => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  383. return 1;
  384. };
  385. unref = []V3_API(void* self) -> uint32_t
  386. {
  387. d_stdout("dpf_edit_controller::unref => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  388. return 0;
  389. };
  390. // ------------------------------------------------------------------------------------------------------------
  391. // v3_plugin_base
  392. base.initialise = []V3_API(void* self, struct v3_plugin_base::v3_funknown *context) -> v3_result
  393. {
  394. d_stdout("dpf_edit_controller::initialise => %s | %p %p", __PRETTY_FUNCTION__ + 53, self, context);
  395. return V3_OK;
  396. };
  397. base.terminate = []V3_API(void* self) -> v3_result
  398. {
  399. d_stdout("dpf_edit_controller::terminate => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  400. return V3_OK;
  401. };
  402. // ------------------------------------------------------------------------------------------------------------
  403. // v3_edit_controller
  404. controller.set_component_state = []V3_API(void* self, v3_bstream*) -> v3_result
  405. {
  406. d_stdout("dpf_edit_controller::set_component_state => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  407. return V3_OK;
  408. };
  409. controller.set_state = []V3_API(void* self, v3_bstream*) -> v3_result
  410. {
  411. d_stdout("dpf_edit_controller::set_state => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  412. return V3_OK;
  413. };
  414. controller.get_state = []V3_API(void* self, v3_bstream*) -> v3_result
  415. {
  416. d_stdout("dpf_edit_controller::get_state => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  417. return V3_OK;
  418. };
  419. controller.get_parameter_count = []V3_API(void* self) -> int32_t
  420. {
  421. d_stdout("dpf_edit_controller::get_parameter_count => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  422. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  423. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_INVALID_ARG);
  424. PluginVst3* const vst3 = controller->vst3.get();
  425. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  426. return vst3->getParameterCount();
  427. };
  428. controller.get_parameter_info = []V3_API(void* self, int32_t param_idx, v3_param_info* param_info) -> v3_result
  429. {
  430. d_stdout("dpf_edit_controller::get_parameter_info => %s | %p %i", __PRETTY_FUNCTION__ + 53, self, param_idx);
  431. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  432. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_INVALID_ARG);
  433. DISTRHO_SAFE_ASSERT_RETURN(param_idx >= 0, V3_INVALID_ARG);
  434. PluginVst3* const vst3 = controller->vst3.get();
  435. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  436. const uint32_t uidx = static_cast<uint32_t>(param_idx);
  437. DISTRHO_SAFE_ASSERT_RETURN(uidx < vst3->getParameterCount(), V3_INVALID_ARG);
  438. vst3->getParameterInfo(uidx, param_info);
  439. return V3_OK;
  440. };
  441. controller.get_parameter_string_for_value = []V3_API(void* self, v3_param_id index, double normalised, v3_str_128 output) -> v3_result
  442. {
  443. d_stdout("dpf_edit_controller::get_parameter_string_for_value => %s | %p %f", __PRETTY_FUNCTION__ + 53, self, normalised);
  444. const ParameterRanges& ranges(gPluginInfo->getParameterRanges(index));
  445. const float realvalue = ranges.getUnnormalizedValue(normalised);
  446. char buf[24];
  447. sprintf(buf, "%f", realvalue);
  448. strncpy_16from8(output, buf, 128);
  449. return V3_OK;
  450. };
  451. controller.get_parameter_value_for_string = []V3_API(void* self, v3_param_id, int16_t* input, double* output) -> v3_result
  452. {
  453. d_stdout("dpf_edit_controller::get_parameter_value_for_string => %s | %p %p %p", __PRETTY_FUNCTION__ + 53, self, input, output);
  454. return V3_NOT_IMPLEMENTED;
  455. };
  456. controller.normalised_parameter_to_plain = []V3_API(void* self, v3_param_id, double normalised) -> double
  457. {
  458. d_stdout("dpf_edit_controller::normalised_parameter_to_plain => %s | %p %f", __PRETTY_FUNCTION__ + 53, self, normalised);
  459. return normalised;
  460. };
  461. controller.plain_parameter_to_normalised = []V3_API(void* self, v3_param_id, double normalised) -> double
  462. {
  463. d_stdout("dpf_edit_controller::plain_parameter_to_normalised => %s | %p %f", __PRETTY_FUNCTION__ + 53, self, normalised);
  464. return normalised;
  465. };
  466. controller.get_parameter_normalised = []V3_API(void* self, v3_param_id param_idx) -> double
  467. {
  468. d_stdout("dpf_edit_controller::get_parameter_normalised => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  469. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  470. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0.0);
  471. PluginVst3* const vst3 = controller->vst3.get();
  472. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0.0);
  473. DISTRHO_SAFE_ASSERT_RETURN(param_idx < vst3->getParameterCount(), 0.0);
  474. return vst3->getNormalizedParameterValue(param_idx);
  475. };
  476. controller.set_parameter_normalised = []V3_API(void* self, v3_param_id param_idx, double normalised) -> v3_result
  477. {
  478. d_stdout("dpf_edit_controller::set_parameter_normalised => %s | %p %f", __PRETTY_FUNCTION__ + 53, self, normalised);
  479. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  480. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_INVALID_ARG);
  481. PluginVst3* const vst3 = controller->vst3.get();
  482. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  483. DISTRHO_SAFE_ASSERT_RETURN(param_idx < vst3->getParameterCount(), V3_INVALID_ARG);
  484. vst3->setNormalizedParameterValue(param_idx, normalised);
  485. return V3_OK;
  486. };
  487. controller.set_component_handler = []V3_API(void* self, v3_component_handler**) -> v3_result
  488. {
  489. d_stdout("dpf_edit_controller::set_component_handler => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  490. return V3_NOT_IMPLEMENTED;
  491. };
  492. controller.create_view = []V3_API(void* self, const char* name) -> v3_plug_view**
  493. {
  494. d_stdout("dpf_edit_controller::create_view => %s | %p %s", __PRETTY_FUNCTION__ + 53, self, name);
  495. return nullptr;
  496. };
  497. }
  498. };
  499. // --------------------------------------------------------------------------------------------------------------------
  500. // dpf_audio_processor
  501. struct v3_audio_processor_cpp : v3_funknown {
  502. v3_audio_processor processor;
  503. };
  504. struct dpf_audio_processor : v3_audio_processor_cpp {
  505. dpf_audio_processor()
  506. {
  507. static const uint8_t* kSupportedFactories[] = {
  508. v3_funknown_iid,
  509. v3_audio_processor_iid
  510. };
  511. // ------------------------------------------------------------------------------------------------------------
  512. // v3_funknown
  513. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  514. {
  515. d_stdout("dpf_audio_processor::query_interface => %s | %p %s %p", __PRETTY_FUNCTION__ + 53, self, tuid2str(iid), iface);
  516. *iface = NULL;
  517. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  518. for (const uint8_t* factory_iid : kSupportedFactories)
  519. {
  520. if (v3_tuid_match(factory_iid, iid))
  521. {
  522. *iface = self;
  523. return V3_OK;
  524. }
  525. }
  526. return V3_NO_INTERFACE;
  527. };
  528. // we only support 1 plugin per binary, so don't have to care here
  529. ref = []V3_API(void* self) -> uint32_t
  530. {
  531. d_stdout("dpf_audio_processor::ref => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  532. return 1;
  533. };
  534. unref = []V3_API(void* self) -> uint32_t
  535. {
  536. d_stdout("dpf_audio_processor::unref => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  537. return 0;
  538. };
  539. // ------------------------------------------------------------------------------------------------------------
  540. // v3_audio_processor
  541. processor.set_bus_arrangements = []V3_API(void* self,
  542. v3_speaker_arrangement* inputs, int32_t num_inputs,
  543. v3_speaker_arrangement* outputs, int32_t num_outputs) -> v3_result
  544. {
  545. d_stdout("dpf_audio_processor::set_bus_arrangements => %s | %p %p %i %p %i", __PRETTY_FUNCTION__ + 53, self, inputs, num_inputs, outputs, num_outputs);
  546. return V3_OK;
  547. };
  548. processor.get_bus_arrangement = []V3_API(void* self, int32_t bus_direction,
  549. int32_t idx, v3_speaker_arrangement*) -> v3_result
  550. {
  551. d_stdout("dpf_audio_processor::get_bus_arrangement => %s | %p %i %i", __PRETTY_FUNCTION__ + 53, self, bus_direction, idx);
  552. return V3_OK;
  553. };
  554. processor.can_process_sample_size = []V3_API(void* self, int32_t symbolic_sample_size) -> v3_result
  555. {
  556. d_stdout("dpf_audio_processor::can_process_sample_size => %s | %p %i", __PRETTY_FUNCTION__ + 53, self, symbolic_sample_size);
  557. return V3_OK;
  558. };
  559. processor.get_latency_samples = []V3_API(void* self) -> uint32_t
  560. {
  561. d_stdout("dpf_audio_processor::get_latency_samples => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  562. return 0;
  563. };
  564. processor.setup_processing = []V3_API(void* self, v3_process_setup* setup) -> v3_result
  565. {
  566. d_stdout("dpf_audio_processor::setup_processing => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  567. d_lastBufferSize = setup->max_block_size;
  568. d_lastSampleRate = setup->sample_rate;
  569. return V3_OK;
  570. };
  571. processor.set_processing = []V3_API(void* self, v3_bool state) -> v3_result
  572. {
  573. d_stdout("dpf_audio_processor::set_processing => %s | %p %u", __PRETTY_FUNCTION__ + 53, self, state);
  574. return V3_OK;
  575. };
  576. processor.process = []V3_API(void* self, v3_process_data*) -> v3_result
  577. {
  578. d_stdout("dpf_audio_processor::process => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  579. return V3_OK;
  580. };
  581. processor.get_tail_samples = []V3_API(void* self) -> uint32_t
  582. {
  583. d_stdout("dpf_audio_processor::get_tail_samples => %s | %p", __PRETTY_FUNCTION__ + 53, self);
  584. return 0;
  585. };
  586. }
  587. };
  588. // --------------------------------------------------------------------------------------------------------------------
  589. // dpf_component
  590. struct v3_component_cpp : v3_funknown {
  591. v3_plugin_base base;
  592. v3_component comp;
  593. };
  594. struct dpf_component : v3_component_cpp {
  595. std::atomic<int> refcounter;
  596. ScopedPointer<dpf_audio_processor> processor;
  597. ScopedPointer<dpf_edit_controller> controller;
  598. ScopedPointer<PluginVst3> vst3;
  599. dpf_component()
  600. : refcounter(1)
  601. {
  602. static const uint8_t* kSupportedBaseFactories[] = {
  603. v3_funknown_iid,
  604. v3_plugin_base_iid,
  605. v3_component_iid
  606. };
  607. // ------------------------------------------------------------------------------------------------------------
  608. // v3_funknown
  609. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  610. {
  611. d_stdout("dpf_component::query_interface => %s | %p %s %p", __PRETTY_FUNCTION__ + 41, self, tuid2str(iid), iface);
  612. *iface = NULL;
  613. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  614. for (const uint8_t* factory_iid : kSupportedBaseFactories)
  615. {
  616. if (v3_tuid_match(factory_iid, iid))
  617. {
  618. *iface = self;
  619. return V3_OK;
  620. }
  621. }
  622. if (v3_tuid_match(v3_audio_processor_iid, iid))
  623. {
  624. dpf_component* const component = *(dpf_component**)self;
  625. if (component->processor == nullptr)
  626. component->processor = new dpf_audio_processor();
  627. *iface = &component->processor;
  628. return V3_OK;
  629. }
  630. if (v3_tuid_match(v3_edit_controller_iid, iid))
  631. {
  632. dpf_component* const component = *(dpf_component**)self;
  633. if (component->controller == nullptr)
  634. component->controller = new dpf_edit_controller(component->vst3);
  635. *iface = &component->controller;
  636. return V3_OK;
  637. }
  638. return V3_NO_INTERFACE;
  639. };
  640. // we only support 1 plugin per binary, so don't have to care here
  641. ref = []V3_API(void* self) -> uint32_t
  642. {
  643. d_stdout("dpf_component::ref => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  644. dpf_component* const component = *(dpf_component**)self;
  645. return ++component->refcounter;
  646. };
  647. unref = []V3_API(void* self) -> uint32_t
  648. {
  649. d_stdout("dpf_component::unref => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  650. dpf_component* const component = *(dpf_component**)self;
  651. if (const int refcounter = --component->refcounter)
  652. return refcounter;
  653. // delete component;
  654. *(dpf_component**)self = nullptr;
  655. return 0;
  656. };
  657. // ------------------------------------------------------------------------------------------------------------
  658. // v3_plugin_base
  659. base.initialise = []V3_API(void* self, struct v3_plugin_base::v3_funknown* context) -> v3_result
  660. {
  661. d_stdout("dpf_component::initialise => %s | %p %p", __PRETTY_FUNCTION__ + 41, self, context);
  662. dpf_component* const component = *(dpf_component**)self;
  663. // default early values
  664. if (d_lastBufferSize == 0)
  665. d_lastBufferSize = 2048;
  666. if (d_lastSampleRate <= 0.0)
  667. d_lastSampleRate = 44100.0;
  668. component->vst3 = new PluginVst3();
  669. return V3_OK;
  670. };
  671. base.terminate = []V3_API(void* self) -> v3_result
  672. {
  673. d_stdout("dpf_component::terminate => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  674. dpf_component* const component = *(dpf_component**)self;
  675. component->vst3 = nullptr;
  676. return V3_OK;
  677. };
  678. // ------------------------------------------------------------------------------------------------------------
  679. // v3_component
  680. comp.get_controller_class_id = []V3_API(void* self, v3_tuid class_id) -> v3_result
  681. {
  682. d_stdout("dpf_component::get_controller_class_id => %s | %p %s", __PRETTY_FUNCTION__ + 41, self, tuid2str(class_id));
  683. return V3_NOT_IMPLEMENTED;
  684. };
  685. comp.set_io_mode = []V3_API(void* self, int32_t io_mode) -> v3_result
  686. {
  687. d_stdout("dpf_component::set_io_mode => %s | %p %i", __PRETTY_FUNCTION__ + 41, self, io_mode);
  688. return V3_INTERNAL_ERR;
  689. };
  690. comp.get_bus_count = []V3_API(void* self, int32_t media_type, int32_t bus_direction) -> int32_t
  691. {
  692. d_stdout("dpf_component::get_bus_count => %s | %p %i %i", __PRETTY_FUNCTION__ + 41, self, media_type, bus_direction);
  693. return 0;
  694. };
  695. comp.get_bus_info = []V3_API(void* self, int32_t media_type, int32_t bus_direction,
  696. int32_t bus_idx, v3_bus_info* bus_info) -> v3_result
  697. {
  698. d_stdout("dpf_component::get_bus_info => %s | %p %i %i %i %p", __PRETTY_FUNCTION__ + 41, self, media_type, bus_direction, bus_idx, bus_info);
  699. return V3_INTERNAL_ERR;
  700. };
  701. comp.get_routing_info = []V3_API(void* self, v3_routing_info* input, v3_routing_info* output) -> v3_result
  702. {
  703. d_stdout("dpf_component::get_routing_info => %s | %p %p %p", __PRETTY_FUNCTION__ + 41, self, input, output);
  704. return V3_INTERNAL_ERR;
  705. };
  706. comp.activate_bus = []V3_API(void* self, int32_t media_type, int32_t bus_direction,
  707. int32_t bus_idx, v3_bool state) -> v3_result
  708. {
  709. d_stdout("dpf_component::activate_bus => %s | %p %i %i %i %u", __PRETTY_FUNCTION__ + 41, self, media_type, bus_direction, bus_idx, state);
  710. return V3_INTERNAL_ERR;
  711. };
  712. comp.set_active = []V3_API(void* self, v3_bool state) -> v3_result
  713. {
  714. d_stdout("dpf_component::set_active => %s | %p %u", __PRETTY_FUNCTION__ + 41, self, state);
  715. return V3_INTERNAL_ERR;
  716. };
  717. comp.set_state = []V3_API(void* self, v3_bstream**) -> v3_result
  718. {
  719. d_stdout("dpf_component::set_state => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  720. return V3_INTERNAL_ERR;
  721. };
  722. comp.get_state = []V3_API(void* self, v3_bstream**) -> v3_result
  723. {
  724. d_stdout("dpf_component::get_state => %s | %p", __PRETTY_FUNCTION__ + 41, self);
  725. return V3_INTERNAL_ERR;
  726. };
  727. }
  728. };
  729. // --------------------------------------------------------------------------------------------------------------------
  730. // dpf_factory
  731. struct v3_plugin_factory_cpp : v3_funknown {
  732. v3_plugin_factory v1;
  733. v3_plugin_factory_2 v2;
  734. v3_plugin_factory_3 v3;
  735. };
  736. struct dpf_factory : v3_plugin_factory_cpp {
  737. std::vector<dpf_component*> components;
  738. dpf_factory()
  739. {
  740. static const uint8_t* kSupportedFactories[] = {
  741. v3_funknown_iid,
  742. v3_plugin_factory_iid,
  743. v3_plugin_factory_2_iid,
  744. v3_plugin_factory_3_iid
  745. };
  746. // ------------------------------------------------------------------------------------------------------------
  747. // v3_funknown
  748. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  749. {
  750. d_stdout("dpf_factory::query_interface => %s | %p %s %p", __PRETTY_FUNCTION__ + 37, self, tuid2str(iid), iface);
  751. *iface = NULL;
  752. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  753. for (const uint8_t* factory_iid : kSupportedFactories)
  754. {
  755. if (v3_tuid_match(factory_iid, iid))
  756. {
  757. *iface = self;
  758. return V3_OK;
  759. }
  760. }
  761. return V3_NO_INTERFACE;
  762. };
  763. // we only support 1 plugin per binary, so don't have to care here
  764. ref = []V3_API(void* self) -> uint32_t
  765. {
  766. d_stdout("dpf_factory::ref => %s | %p", __PRETTY_FUNCTION__ + 37, self);
  767. return 1;
  768. };
  769. unref = []V3_API(void* self) -> uint32_t
  770. {
  771. d_stdout("dpf_factory::unref => %s | %p", __PRETTY_FUNCTION__ + 37, self);
  772. return 0;
  773. };
  774. // ------------------------------------------------------------------------------------------------------------
  775. // v3_plugin_factory
  776. v1.get_factory_info = []V3_API(void* self, struct v3_factory_info* const info) -> v3_result
  777. {
  778. d_stdout("dpf_factory::get_factory_info => %s | %p %p", __PRETTY_FUNCTION__ + 37, self, info);
  779. DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo->getMaker(), sizeof(info->vendor));
  780. DISTRHO_NAMESPACE::strncpy(info->url, gPluginInfo->getHomePage(), sizeof(info->url));
  781. DISTRHO_NAMESPACE::strncpy(info->email, "", sizeof(info->email)); // TODO
  782. return V3_OK;
  783. };
  784. v1.num_classes = []V3_API(void* self) -> int32_t
  785. {
  786. d_stdout("dpf_factory::num_classes => %s | %p", __PRETTY_FUNCTION__ + 37, self);
  787. return 1;
  788. };
  789. v1.get_class_info = []V3_API(void* self, int32_t idx, struct v3_class_info* const info) -> v3_result
  790. {
  791. d_stdout("dpf_factory::get_class_info => %s | %p %i %p", __PRETTY_FUNCTION__ + 37, self, idx, info);
  792. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  793. memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  794. info->cardinality = 0x7FFFFFFF;
  795. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
  796. DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo->getName(), sizeof(info->name));
  797. return V3_OK;
  798. };
  799. v1.create_instance = []V3_API(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance) -> v3_result
  800. {
  801. d_stdout("dpf_factory::create_instance => %s | %p %s %s %p", __PRETTY_FUNCTION__ + 37, self, tuid2str(class_id), tuid2str(iid), instance);
  802. DISTRHO_SAFE_ASSERT_RETURN(v3_tuid_match(class_id, *(v3_tuid*)&dpf_tuid_class) &&
  803. v3_tuid_match(iid, v3_component_iid), V3_NO_INTERFACE);
  804. dpf_factory* const factory = *(dpf_factory**)self;
  805. dpf_component* const component = new dpf_component();
  806. factory->components.push_back(component);
  807. *instance = &factory->components.back();
  808. return V3_OK;
  809. };
  810. // ------------------------------------------------------------------------------------------------------------
  811. // v3_plugin_factory_2
  812. v2.get_class_info_2 = []V3_API(void* self, int32_t idx, struct v3_class_info_2* info) -> v3_result
  813. {
  814. d_stdout("dpf_factory::get_class_info_2 => %s | %p %i %p", __PRETTY_FUNCTION__ + 37, self, idx, info);
  815. memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  816. info->cardinality = 0x7FFFFFFF;
  817. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
  818. DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo->getName(), sizeof(info->name));
  819. info->class_flags = 0;
  820. DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO
  821. DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo->getMaker(), sizeof(info->vendor));
  822. std::snprintf(info->version, sizeof(info->version), "%u", gPluginInfo->getVersion()); // TODO
  823. DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", sizeof(info->sdk_version)); // TESTING use "VST 3.7" ?
  824. return V3_OK;
  825. };
  826. // ------------------------------------------------------------------------------------------------------------
  827. // v3_plugin_factory_3
  828. v3.get_class_info_utf16 = []V3_API(void* self, int32_t idx, struct v3_class_info_3* info) -> v3_result
  829. {
  830. d_stdout("dpf_factory::get_class_info_utf16 => %s | %p %i %p", __PRETTY_FUNCTION__ + 37, self, idx, info);
  831. memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  832. info->cardinality = 0x7FFFFFFF;
  833. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
  834. DISTRHO_NAMESPACE::strncpy_16from8(info->name, gPluginInfo->getName(), sizeof(info->name));
  835. info->class_flags = 0;
  836. DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO
  837. DISTRHO_NAMESPACE::strncpy_16from8(info->vendor, gPluginInfo->getMaker(), sizeof(info->vendor));
  838. // DISTRHO_NAMESPACE::snprintf16(info->version, sizeof(info->version)/sizeof(info->version[0]), "%u", gPluginInfo->getVersion()); // TODO
  839. DISTRHO_NAMESPACE::strncpy_16from8(info->sdk_version, "Travesty", sizeof(info->sdk_version)); // TESTING use "VST 3.7" ?
  840. return V3_OK;
  841. };
  842. v3.set_host_context = []V3_API (void* self, struct v3_funknown* host) -> v3_result
  843. {
  844. d_stdout("dpf_factory::set_host_context => %s | %p %p", __PRETTY_FUNCTION__ + 37, self, host);
  845. return V3_NOT_IMPLEMENTED;
  846. };
  847. }
  848. };
  849. END_NAMESPACE_DISTRHO
  850. // --------------------------------------------------------------------------------------------------------------------
  851. // VST3 entry point
  852. DISTRHO_PLUGIN_EXPORT
  853. const void* GetPluginFactory(void);
  854. const void* GetPluginFactory(void)
  855. {
  856. USE_NAMESPACE_DISTRHO;
  857. static const dpf_factory factory;
  858. static const v3_funknown* const factoryptr = &factory;
  859. return &factoryptr;
  860. }
  861. // --------------------------------------------------------------------------------------------------------------------
  862. // OS specific module load
  863. #if defined(DISTRHO_OS_MAC)
  864. # define ENTRYFNNAME bundleEntry
  865. # define EXITFNNAME bundleExit
  866. #elif defined(DISTRHO_OS_WINDOWS)
  867. # define ENTRYFNNAME InitDll
  868. # define EXITFNNAME ExitDll
  869. #else
  870. # define ENTRYFNNAME ModuleEntry
  871. # define EXITFNNAME ModuleExit
  872. #endif
  873. DISTRHO_PLUGIN_EXPORT
  874. bool ENTRYFNNAME(void*);
  875. bool ENTRYFNNAME(void*)
  876. {
  877. USE_NAMESPACE_DISTRHO;
  878. if (gPluginInfo == nullptr)
  879. {
  880. d_lastBufferSize = 512;
  881. d_lastSampleRate = 44100.0;
  882. gPluginInfo = new PluginExporter(nullptr, nullptr, nullptr);
  883. d_lastBufferSize = 0;
  884. d_lastSampleRate = 0.0;
  885. dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2]
  886. = dpf_tuid_processor[2] = dpf_tuid_view[2] = gPluginInfo->getUniqueId();
  887. }
  888. return true;
  889. }
  890. DISTRHO_PLUGIN_EXPORT
  891. bool EXITFNNAME(void);
  892. bool EXITFNNAME(void)
  893. {
  894. USE_NAMESPACE_DISTRHO;
  895. gPluginInfo = nullptr;
  896. return true;
  897. }
  898. #undef ENTRYFNNAME
  899. #undef EXITFNNAME
  900. // --------------------------------------------------------------------------------------------------------------------