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.

2337 lines
87KB

  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. // TESTING awful idea dont reuse
  24. #include "../extra/Thread.hpp"
  25. START_NAMESPACE_DISTRHO
  26. // --------------------------------------------------------------------------------------------------------------------
  27. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  28. static const writeMidiFunc writeMidiCallback = nullptr;
  29. #endif
  30. #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  31. static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
  32. #endif
  33. // --------------------------------------------------------------------------------------------------------------------
  34. // custom v3_tuid compatible type
  35. typedef uint32_t dpf_tuid[4];
  36. static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch");
  37. // --------------------------------------------------------------------------------------------------------------------
  38. // custom, constant uids related to DPF
  39. static constexpr const uint32_t dpf_id_entry = d_cconst('D', 'P', 'F', ' ');
  40. static constexpr const uint32_t dpf_id_clas = d_cconst('c', 'l', 'a', 's');
  41. static constexpr const uint32_t dpf_id_comp = d_cconst('c', 'o', 'm', 'p');
  42. static constexpr const uint32_t dpf_id_ctrl = d_cconst('c', 't', 'r', 'l');
  43. static constexpr const uint32_t dpf_id_proc = d_cconst('p', 'r', 'o', 'c');
  44. static constexpr const uint32_t dpf_id_view = d_cconst('v', 'i', 'e', 'w');
  45. // --------------------------------------------------------------------------------------------------------------------
  46. // plugin specific uids (values are filled in during plugin init)
  47. static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, 0 };
  48. static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, 0 };
  49. static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, 0 };
  50. static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, 0 };
  51. static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 };
  52. // --------------------------------------------------------------------------------------------------------------------
  53. // Utility functions
  54. static const char* tuid2str(const v3_tuid iid)
  55. {
  56. if (v3_tuid_match(iid, v3_funknown_iid))
  57. return "{v3_funknown}";
  58. if (v3_tuid_match(iid, v3_plugin_base_iid))
  59. return "{v3_plugin_base}";
  60. if (v3_tuid_match(iid, v3_plugin_factory_iid))
  61. return "{v3_plugin_factory}";
  62. if (v3_tuid_match(iid, v3_plugin_factory_2_iid))
  63. return "{v3_plugin_factory_2}";
  64. if (v3_tuid_match(iid, v3_plugin_factory_3_iid))
  65. return "{v3_plugin_factory_3}";
  66. if (v3_tuid_match(iid, v3_component_iid))
  67. return "{v3_component}";
  68. if (v3_tuid_match(iid, v3_bstream_iid))
  69. return "{v3_bstream}";
  70. if (v3_tuid_match(iid, v3_event_list_iid))
  71. return "{v3_event_list}";
  72. if (v3_tuid_match(iid, v3_param_value_queue_iid))
  73. return "{v3_param_value_queue}";
  74. if (v3_tuid_match(iid, v3_param_changes_iid))
  75. return "{v3_param_changes}";
  76. if (v3_tuid_match(iid, v3_process_context_requirements_iid))
  77. return "{v3_process_context_requirements}";
  78. if (v3_tuid_match(iid, v3_audio_processor_iid))
  79. return "{v3_audio_processor}";
  80. if (v3_tuid_match(iid, v3_component_handler_iid))
  81. return "{v3_component_handler}";
  82. if (v3_tuid_match(iid, v3_edit_controller_iid))
  83. return "{v3_edit_controller}";
  84. if (v3_tuid_match(iid, v3_plugin_view_iid))
  85. return "{v3_plugin_view}";
  86. if (v3_tuid_match(iid, v3_plugin_frame_iid))
  87. return "{v3_plugin_frame}";
  88. if (v3_tuid_match(iid, v3_plugin_view_content_scale_steinberg_iid))
  89. return "{v3_plugin_view_content_scale_steinberg}";
  90. if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid))
  91. return "{v3_plugin_view_parameter_finder}";
  92. if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0)
  93. return "{dpf_tuid_class}";
  94. if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0)
  95. return "{dpf_tuid_component}";
  96. if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0)
  97. return "{dpf_tuid_controller}";
  98. if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0)
  99. return "{dpf_tuid_processor}";
  100. if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0)
  101. return "{dpf_tuid_view}";
  102. static char buf[46];
  103. std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}",
  104. (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
  105. (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]),
  106. (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]),
  107. (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15]));
  108. return buf;
  109. }
  110. // --------------------------------------------------------------------------------------------------------------------
  111. static void strncpy(char* const dst, const char* const src, const size_t size)
  112. {
  113. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  114. if (const size_t len = std::min(std::strlen(src), size-1U))
  115. {
  116. std::memcpy(dst, src, len);
  117. dst[len] = '\0';
  118. }
  119. else
  120. {
  121. dst[0] = '\0';
  122. }
  123. }
  124. static void strncpy_utf16(int16_t* const dst, const char* const src, const size_t size)
  125. {
  126. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  127. if (const size_t len = std::min(std::strlen(src), size-1U))
  128. {
  129. for (size_t i=0; i<len; ++i)
  130. {
  131. // skip non-ascii chars
  132. if ((uint8_t)src[i] >= 0x80)
  133. continue;
  134. dst[i] = src[i];
  135. }
  136. dst[len] = 0;
  137. }
  138. else
  139. {
  140. dst[0] = 0;
  141. }
  142. }
  143. // --------------------------------------------------------------------------------------------------------------------
  144. template<typename T, const char* const format>
  145. static void snprintf_t(char* const dst, const T value, const size_t size)
  146. {
  147. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  148. std::snprintf(dst, size-1, format, value);
  149. dst[size-1] = '\0';
  150. }
  151. template<typename T, const char* const format>
  152. static void snprintf_utf16_t(int16_t* const dst, const T value, const size_t size)
  153. {
  154. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  155. char* const tmpbuf = (char*)std::malloc(size);
  156. DISTRHO_SAFE_ASSERT_RETURN(tmpbuf != nullptr,);
  157. std::snprintf(tmpbuf, size-1, format, value);
  158. tmpbuf[size-1] = '\0';
  159. strncpy_utf16(dst, tmpbuf, size);
  160. std::free(tmpbuf);
  161. }
  162. static constexpr const char format_i32[] = "%d";
  163. static constexpr const char format_f32[] = "%f";
  164. static constexpr const char format_u32[] = "%u";
  165. static constexpr void (*const snprintf_u32)(char*, uint32_t, size_t) = snprintf_t<uint32_t, format_u32>;
  166. static constexpr void (*const snprintf_f32_utf16)(int16_t*, float, size_t) = snprintf_utf16_t<float, format_f32>;
  167. static constexpr void (*const snprintf_u32_utf16)(int16_t*, uint32_t, size_t) = snprintf_utf16_t<uint32_t, format_u32>;
  168. // --------------------------------------------------------------------------------------------------------------------
  169. class PluginVst3
  170. {
  171. /* buses: we provide 1 for the main audio (if there is any) plus 1 for each sidechain or cv port.
  172. * Main audio comes first, if available.
  173. * Then sidechain, also if available.
  174. * And finally each CV port individually.
  175. *
  176. * MIDI will have a single bus, nothing special there.
  177. */
  178. struct BusInfo {
  179. uint8_t audio = 0; // either 0 or 1
  180. uint8_t sidechain = 0; // either 0 or 1
  181. uint32_t numMainAudio = 0;
  182. uint32_t numSidechain = 0;
  183. uint32_t numCV = 0;
  184. } inputBuses, outputBuses;
  185. public:
  186. PluginVst3()
  187. : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback),
  188. fComponentHandler(nullptr),
  189. fComponentHandlerArg(nullptr)
  190. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  191. , fHostEventOutputHandle(nullptr)
  192. #endif
  193. {
  194. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  195. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  196. {
  197. const uint32_t hints = fPlugin.getAudioPortHints(true, i);
  198. if (hints & kAudioPortIsCV)
  199. ++inputBuses.numCV;
  200. else
  201. ++inputBuses.numMainAudio;
  202. if (hints & kAudioPortIsSidechain)
  203. ++inputBuses.numSidechain;
  204. }
  205. if (inputBuses.numMainAudio != 0)
  206. inputBuses.audio = 1;
  207. if (inputBuses.numSidechain != 0)
  208. inputBuses.sidechain = 1;
  209. uint32_t cvInputBusId = 0;
  210. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  211. {
  212. AudioPortWithBusId& port(fPlugin.getAudioPort(true, i));
  213. if (port.hints & kAudioPortIsCV)
  214. port.busId = inputBuses.audio + inputBuses.sidechain + cvInputBusId++;
  215. else if (port.hints & kAudioPortIsSidechain)
  216. port.busId = 1;
  217. else
  218. port.busId = 0;
  219. }
  220. #endif
  221. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  222. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  223. {
  224. const uint32_t hints = fPlugin.getAudioPortHints(false, i);
  225. if (hints & kAudioPortIsCV)
  226. ++outputBuses.numCV;
  227. else
  228. ++outputBuses.numMainAudio;
  229. if (hints & kAudioPortIsSidechain)
  230. ++outputBuses.numSidechain;
  231. }
  232. if (outputBuses.numMainAudio != 0)
  233. outputBuses.audio = 1;
  234. if (outputBuses.numSidechain != 0)
  235. outputBuses.sidechain = 1;
  236. uint32_t cvOutputBusId = 0;
  237. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  238. {
  239. AudioPortWithBusId& port(fPlugin.getAudioPort(false, i));
  240. if (port.hints & kAudioPortIsCV)
  241. port.busId = outputBuses.audio + outputBuses.sidechain + cvOutputBusId++;
  242. else if (port.hints & kAudioPortIsSidechain)
  243. port.busId = 1;
  244. else
  245. port.busId = 0;
  246. }
  247. #endif
  248. }
  249. // ----------------------------------------------------------------------------------------------------------------
  250. // stuff called for UI creation
  251. void* getInstancePointer() const noexcept
  252. {
  253. return fPlugin.getInstancePointer();
  254. }
  255. double getSampleRate() const noexcept
  256. {
  257. return fPlugin.getSampleRate();
  258. }
  259. // ----------------------------------------------------------------------------------------------------------------
  260. // v3_component interface calls
  261. int32_t getBusCount(const int32_t mediaType, const int32_t busDirection) const noexcept
  262. {
  263. switch (mediaType)
  264. {
  265. case V3_AUDIO:
  266. if (busDirection == V3_INPUT)
  267. return inputBuses.audio + inputBuses.sidechain + inputBuses.numCV;
  268. if (busDirection == V3_OUTPUT)
  269. return outputBuses.audio + outputBuses.sidechain + outputBuses.numCV;
  270. break;
  271. case V3_EVENT:
  272. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  273. if (busDirection == V3_INPUT)
  274. return 1;
  275. #endif
  276. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  277. if (busDirection == V3_OUTPUT)
  278. return 1;
  279. #endif
  280. break;
  281. }
  282. return 0;
  283. }
  284. v3_result getBusInfo(const int32_t mediaType,
  285. const int32_t busDirection,
  286. const int32_t busIndex,
  287. v3_bus_info* const info) const
  288. {
  289. DISTRHO_SAFE_ASSERT_INT_RETURN(mediaType == V3_AUDIO || mediaType == V3_EVENT, mediaType, V3_INVALID_ARG);
  290. DISTRHO_SAFE_ASSERT_INT_RETURN(busDirection == V3_INPUT || busDirection == V3_OUTPUT, busDirection, V3_INVALID_ARG);
  291. DISTRHO_SAFE_ASSERT_INT_RETURN(busIndex >= 0, busIndex, V3_INVALID_ARG);
  292. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 || DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  293. const uint32_t busId = static_cast<uint32_t>(busIndex);
  294. #endif
  295. if (mediaType == V3_AUDIO)
  296. {
  297. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  298. int32_t numChannels;
  299. v3_bus_flags flags;
  300. v3_bus_types busType;
  301. v3_str_128 busName = {};
  302. if (busDirection == V3_INPUT)
  303. {
  304. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  305. switch (busId)
  306. {
  307. case 0:
  308. if (inputBuses.audio)
  309. {
  310. numChannels = inputBuses.numMainAudio;
  311. busType = V3_MAIN;
  312. flags = V3_DEFAULT_ACTIVE;
  313. break;
  314. }
  315. // fall-through
  316. case 1:
  317. if (inputBuses.sidechain)
  318. {
  319. numChannels = inputBuses.numSidechain;
  320. busType = V3_AUX;
  321. flags = v3_bus_flags(0);
  322. break;
  323. }
  324. // fall-through
  325. default:
  326. numChannels = 1;
  327. busType = V3_AUX;
  328. flags = V3_IS_CONTROL_VOLTAGE;
  329. break;
  330. }
  331. if (busType == V3_MAIN)
  332. {
  333. strncpy_utf16(busName, "Audio Input", 128);
  334. }
  335. else
  336. {
  337. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  338. {
  339. const AudioPortWithBusId& port(fPlugin.getAudioPort(true, i));
  340. // TODO find port group name
  341. if (port.busId == busId)
  342. {
  343. strncpy_utf16(busName, port.name, 128);
  344. break;
  345. }
  346. }
  347. }
  348. #else
  349. return V3_INVALID_ARG;
  350. #endif // DISTRHO_PLUGIN_NUM_INPUTS
  351. }
  352. else
  353. {
  354. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  355. switch (busId)
  356. {
  357. case 0:
  358. if (outputBuses.audio)
  359. {
  360. numChannels = outputBuses.numMainAudio;
  361. busType = V3_MAIN;
  362. flags = V3_DEFAULT_ACTIVE;
  363. break;
  364. }
  365. // fall-through
  366. case 1:
  367. if (outputBuses.sidechain)
  368. {
  369. numChannels = outputBuses.numSidechain;
  370. busType = V3_AUX;
  371. flags = v3_bus_flags(0);
  372. break;
  373. }
  374. // fall-through
  375. default:
  376. numChannels = 1;
  377. busType = V3_AUX;
  378. flags = V3_IS_CONTROL_VOLTAGE;
  379. break;
  380. }
  381. if (busType == V3_MAIN)
  382. {
  383. strncpy_utf16(busName, "Audio Output", 128);
  384. }
  385. else
  386. {
  387. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  388. {
  389. const AudioPortWithBusId& port(fPlugin.getAudioPort(false, i));
  390. // TODO find port group name
  391. if (port.busId == busId)
  392. {
  393. strncpy_utf16(busName, port.name, 128);
  394. break;
  395. }
  396. }
  397. }
  398. #else
  399. return V3_INVALID_ARG;
  400. #endif // DISTRHO_PLUGIN_NUM_OUTPUTS
  401. }
  402. std::memset(info, 0, sizeof(v3_bus_info));
  403. info->media_type = V3_AUDIO;
  404. info->direction = busDirection;
  405. info->channel_count = numChannels;
  406. std::memcpy(info->bus_name, busName, sizeof(busName));
  407. info->bus_type = busType;
  408. info->flags = flags;
  409. return V3_OK;
  410. #else
  411. return V3_INVALID_ARG;
  412. #endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS
  413. }
  414. else
  415. {
  416. if (busDirection == V3_INPUT)
  417. {
  418. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  419. DISTRHO_SAFE_ASSERT_RETURN(busId == 0, V3_INVALID_ARG);
  420. #else
  421. return V3_INVALID_ARG;
  422. #endif
  423. }
  424. else
  425. {
  426. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  427. DISTRHO_SAFE_ASSERT_RETURN(busId == 0, V3_INVALID_ARG);
  428. #else
  429. return V3_INVALID_ARG;
  430. #endif
  431. }
  432. info->media_type = V3_EVENT;
  433. info->direction = busDirection;
  434. info->channel_count = 1;
  435. strncpy_utf16(info->bus_name, busDirection == V3_INPUT ? "Event/MIDI Input"
  436. : "Event/MIDI Output", 128);
  437. info->bus_type = V3_MAIN;
  438. info->flags = V3_DEFAULT_ACTIVE;
  439. return V3_OK;
  440. }
  441. }
  442. v3_result getRoutingInfo(v3_routing_info*, v3_routing_info*)
  443. {
  444. // TODO
  445. return V3_NOT_IMPLEMENTED;
  446. }
  447. v3_result activateBus(const int32_t /* mediaType */,
  448. const int32_t /* busDirection */,
  449. const int32_t /* busIndex */,
  450. const bool /* state */)
  451. {
  452. // TODO, returning ok to make bitwig happy
  453. return V3_OK;
  454. }
  455. v3_result setActive(const bool active)
  456. {
  457. if (active)
  458. fPlugin.activate();
  459. else
  460. fPlugin.deactivateIfNeeded();
  461. return V3_OK;
  462. }
  463. /* state: we pack pairs of key-value strings each separated by a null/zero byte.
  464. * states come first, and then parameters. parameters are simply converted to/from strings and floats.
  465. * the parameter symbol is used as the "key", so it is possible to reorder them or even remove and add safely.
  466. * the number of states must remain constant though.
  467. */
  468. v3_result setState(v3_bstream* const stream, void* arg)
  469. {
  470. #if DISTRHO_PLUGIN_WANT_STATE
  471. // TODO
  472. #endif
  473. if (const uint32_t paramCount = fPlugin.getParameterCount())
  474. {
  475. char buffer[32], orig;
  476. String key, value;
  477. v3_result res;
  478. bool fillingKey = true;
  479. // temporarily set locale to "C" while converting floats
  480. const ScopedSafeLocale ssl;
  481. for (int32_t pos = 0, read;; pos += read)
  482. {
  483. std::memset(buffer, '\xff', sizeof(buffer));
  484. res = stream->read(arg, buffer, sizeof(buffer)-1, &read);
  485. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  486. DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR);
  487. for (int32_t i = 0; i < read; ++i)
  488. {
  489. if (buffer[i] == '\0' && pos == 0 && i == 0)
  490. continue;
  491. orig = buffer[read];
  492. buffer[read] = '\0';
  493. if (fillingKey)
  494. key += buffer + i;
  495. else
  496. value += buffer + i;
  497. i += std::strlen(buffer + i);
  498. buffer[read] = orig;
  499. if (buffer[i] == '\0')
  500. {
  501. fillingKey = !fillingKey;
  502. if (value.isNotEmpty())
  503. {
  504. // find parameter with this symbol, and set its value
  505. for (uint32_t j=0; j<paramCount; ++j)
  506. {
  507. if (fPlugin.isParameterOutputOrTrigger(j))
  508. continue;
  509. if (fPlugin.getParameterSymbol(j) != key)
  510. continue;
  511. fPlugin.setParameterValue(j, std::atof(value.buffer()));
  512. break;
  513. }
  514. key.clear();
  515. value.clear();
  516. }
  517. if (buffer[i+1] == '\0')
  518. return V3_OK;
  519. }
  520. }
  521. if (buffer[read] == '\0')
  522. return V3_OK;
  523. }
  524. }
  525. return V3_OK;
  526. }
  527. v3_result getState(v3_bstream* const stream, void* arg)
  528. {
  529. const uint32_t paramCount = fPlugin.getParameterCount();
  530. #if DISTRHO_PLUGIN_WANT_STATE
  531. const uint32_t stateCount = fPlugin.getStateCount();
  532. #else
  533. const uint32_t stateCount = 0;
  534. #endif
  535. if (stateCount == 0 && paramCount == 0)
  536. {
  537. char buffer = '\0';
  538. int32_t ignored;
  539. return stream->write(arg, &buffer, 1, &ignored);
  540. }
  541. String state;
  542. #if DISTRHO_PLUGIN_WANT_FULL_STATE
  543. /*
  544. // Update current state
  545. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  546. {
  547. const String& key = cit->first;
  548. fStateMap[key] = fPlugin.getState(key);
  549. }
  550. */
  551. #endif
  552. #if DISTRHO_PLUGIN_WANT_STATE
  553. /*
  554. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  555. {
  556. const String& key = cit->first;
  557. const String& value = cit->second;
  558. // join key and value
  559. String tmpStr;
  560. tmpStr = key;
  561. tmpStr += "\xff";
  562. tmpStr += value;
  563. tmpStr += "\xff";
  564. state += tmpStr;
  565. }
  566. */
  567. #endif
  568. if (paramCount != 0)
  569. {
  570. // add another separator
  571. state += "\xff";
  572. for (uint32_t i=0; i<paramCount; ++i)
  573. {
  574. if (fPlugin.isParameterOutputOrTrigger(i))
  575. continue;
  576. // join key and value
  577. String tmpStr;
  578. tmpStr = fPlugin.getParameterSymbol(i);
  579. tmpStr += "\xff";
  580. tmpStr += String(fPlugin.getParameterValue(i));
  581. tmpStr += "\xff";
  582. state += tmpStr;
  583. }
  584. }
  585. state.replace('\xff', '\0');
  586. // now saving state, carefully until host written bytes matches full state size
  587. const char* buffer = state.buffer();
  588. const int32_t size = static_cast<int32_t>(state.length())+1;
  589. v3_result res;
  590. for (int32_t wrtntotal = 0, wrtn; wrtntotal < size; wrtntotal += wrtn)
  591. {
  592. wrtn = 0;
  593. res = stream->write(arg, const_cast<char*>(buffer), size - wrtntotal, &wrtn);
  594. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  595. DISTRHO_SAFE_ASSERT_INT_RETURN(wrtn > 0, wrtn, V3_INTERNAL_ERR);
  596. }
  597. return V3_OK;
  598. }
  599. // ----------------------------------------------------------------------------------------------------------------
  600. // v3_bstream interface calls (for state support)
  601. v3_result read(void* /*buffer*/, int32_t /*num_bytes*/, int32_t* /*bytes_read*/)
  602. {
  603. // TODO
  604. return V3_NOT_IMPLEMENTED;
  605. }
  606. v3_result write(void* /*buffer*/, int32_t /*num_bytes*/, int32_t* /*bytes_written*/)
  607. {
  608. // TODO
  609. return V3_NOT_IMPLEMENTED;
  610. }
  611. v3_result seek(int64_t /*pos*/, int32_t /*seek_mode*/, int64_t* /*result*/)
  612. {
  613. // TODO
  614. return V3_NOT_IMPLEMENTED;
  615. }
  616. v3_result tell(int64_t* /*pos*/)
  617. {
  618. // TODO
  619. return V3_NOT_IMPLEMENTED;
  620. }
  621. // ----------------------------------------------------------------------------------------------------------------
  622. // v3_audio_processor interface calls
  623. v3_result setBusArrangements(v3_speaker_arrangement*, int32_t, v3_speaker_arrangement*, int32_t)
  624. {
  625. // TODO
  626. return V3_NOT_IMPLEMENTED;
  627. }
  628. v3_result getBusArrangement(int32_t, int32_t, v3_speaker_arrangement*)
  629. {
  630. // TODO
  631. return V3_NOT_IMPLEMENTED;
  632. };
  633. uint32_t getLatencySamples() const noexcept
  634. {
  635. #if DISTRHO_PLUGIN_WANT_LATENCY
  636. return fPlugin.getLatency();
  637. #else
  638. return 0;
  639. #endif
  640. }
  641. v3_result setupProcessing(v3_process_setup* const setup)
  642. {
  643. DISTRHO_SAFE_ASSERT_RETURN(setup->symbolic_sample_size == V3_SAMPLE_32, V3_INVALID_ARG);
  644. const bool active = fPlugin.isActive();
  645. fPlugin.deactivateIfNeeded();
  646. // TODO process_mode can be V3_REALTIME, V3_PREFETCH, V3_OFFLINE
  647. fPlugin.setSampleRate(setup->sample_rate, true);
  648. fPlugin.setBufferSize(setup->max_block_size, true);
  649. if (active)
  650. fPlugin.activate();
  651. // TODO create dummy buffer of max_block_size length, to use for disabled buses
  652. return V3_OK;
  653. }
  654. v3_result setProcessing(const bool processing)
  655. {
  656. if (processing)
  657. {
  658. if (! fPlugin.isActive())
  659. fPlugin.activate();
  660. }
  661. else
  662. {
  663. fPlugin.deactivate();
  664. }
  665. return V3_OK;
  666. }
  667. v3_result process(v3_process_data* const data)
  668. {
  669. DISTRHO_SAFE_ASSERT_RETURN(data->symbolic_sample_size == V3_SAMPLE_32, V3_INVALID_ARG);
  670. if (! fPlugin.isActive())
  671. {
  672. // host has not activated the plugin yet, nasty!
  673. fPlugin.activate();
  674. }
  675. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  676. if (v3_process_context* const ctx = data->ctx)
  677. {
  678. fTimePosition.playing = ctx->state & V3_PROCESS_CTX_PLAYING;
  679. fTimePosition.bbt.valid = ctx->state & (V3_PROCESS_CTX_TEMPO_VALID|V3_PROCESS_CTX_TIME_SIG_VALID);
  680. // ticksPerBeat is not possible with VST2
  681. fTimePosition.bbt.ticksPerBeat = 1920.0;
  682. if (ctx->state & V3_PROCESS_CTX_CONT_TIME_VALID)
  683. fTimePosition.frame = ctx->continuous_time_in_samples;
  684. else
  685. fTimePosition.frame = ctx->project_time_in_samples;
  686. if (ctx->state & V3_PROCESS_CTX_TEMPO_VALID)
  687. fTimePosition.bbt.beatsPerMinute = ctx->bpm;
  688. else
  689. fTimePosition.bbt.beatsPerMinute = 120.0;
  690. if (ctx->state & (V3_PROCESS_CTX_PROJECT_TIME_VALID|V3_PROCESS_CTX_TIME_SIG_VALID))
  691. {
  692. const double ppqPos = std::abs(ctx->project_time_quarters);
  693. const int ppqPerBar = ctx->time_sig_numerator * 4 / ctx->time_sig_denom;
  694. const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * ctx->time_sig_numerator;
  695. const double rest = std::fmod(barBeats, 1.0);
  696. fTimePosition.bbt.bar = static_cast<int32_t>(ppqPos) / ppqPerBar + 1;
  697. fTimePosition.bbt.beat = static_cast<int32_t>(barBeats - rest + 0.5) + 1;
  698. fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
  699. fTimePosition.bbt.beatsPerBar = ctx->time_sig_numerator;
  700. fTimePosition.bbt.beatType = ctx->time_sig_denom;
  701. if (ctx->project_time_quarters < 0.0)
  702. {
  703. --fTimePosition.bbt.bar;
  704. fTimePosition.bbt.beat = ctx->time_sig_numerator - fTimePosition.bbt.beat + 1;
  705. fTimePosition.bbt.tick = fTimePosition.bbt.ticksPerBeat - fTimePosition.bbt.tick - 1;
  706. }
  707. }
  708. else
  709. {
  710. fTimePosition.bbt.bar = 1;
  711. fTimePosition.bbt.beat = 1;
  712. fTimePosition.bbt.tick = 0.0;
  713. fTimePosition.bbt.beatsPerBar = 4.0f;
  714. fTimePosition.bbt.beatType = 4.0f;
  715. }
  716. fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*
  717. fTimePosition.bbt.beatsPerBar*
  718. (fTimePosition.bbt.bar-1);
  719. fPlugin.setTimePosition(fTimePosition);
  720. }
  721. #endif
  722. const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS != 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1];
  723. /* */ float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS != 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1];
  724. {
  725. int32_t i = 0;
  726. if (data->inputs != nullptr)
  727. {
  728. for (; i < data->inputs->num_channels; ++i)
  729. {
  730. DISTRHO_SAFE_ASSERT_INT_BREAK(i < DISTRHO_PLUGIN_NUM_INPUTS, i);
  731. inputs[i] = data->inputs->channel_buffers_32[i];
  732. }
  733. }
  734. for (; i < std::max(1, DISTRHO_PLUGIN_NUM_INPUTS); ++i)
  735. inputs[i] = nullptr; // TODO use dummy buffer
  736. }
  737. {
  738. int32_t i = 0;
  739. if (data->outputs != nullptr)
  740. {
  741. for (; i < data->outputs->num_channels; ++i)
  742. {
  743. DISTRHO_SAFE_ASSERT_INT_BREAK(i < DISTRHO_PLUGIN_NUM_OUTPUTS, i);
  744. outputs[i] = data->outputs->channel_buffers_32[i];
  745. }
  746. }
  747. for (; i < std::max(1, DISTRHO_PLUGIN_NUM_OUTPUTS); ++i)
  748. outputs[i] = nullptr; // TODO use dummy buffer
  749. }
  750. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  751. fHostEventOutputHandle = data->output_events;
  752. #endif
  753. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  754. uint32_t midiEventCount = 0;
  755. if (v3_event_list** const eventarg = data->input_events)
  756. {
  757. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  758. v3_event_list* const eventptr = (v3_event_list*)((uint8_t*)(*eventarg)+sizeof(v3_funknown));
  759. v3_event event;
  760. for (uint32_t i = 0, count = eventptr->get_event_count(eventarg); i < count; ++i)
  761. {
  762. if (eventptr->get_event(eventarg, i, &event) != V3_OK)
  763. break;
  764. // check if event can be encoded as MIDI
  765. switch (event.type)
  766. {
  767. case V3_EVENT_NOTE_ON:
  768. case V3_EVENT_NOTE_OFF:
  769. // case V3_EVENT_DATA:
  770. case V3_EVENT_POLY_PRESSURE:
  771. // case V3_EVENT_NOTE_EXP_VALUE:
  772. // case V3_EVENT_NOTE_EXP_TEXT:
  773. // case V3_EVENT_CHORD:
  774. // case V3_EVENT_SCALE:
  775. case V3_EVENT_LEGACY_MIDI_CC_OUT:
  776. break;
  777. default:
  778. continue;
  779. }
  780. MidiEvent& midiEvent(fMidiEvents[midiEventCount++]);
  781. midiEvent.frame = event.sample_offset;
  782. // encode event as MIDI
  783. switch (event.type)
  784. {
  785. case V3_EVENT_NOTE_ON:
  786. midiEvent.size = 3;
  787. midiEvent.data[0] = 0x90 | (event.note_on.channel & 0xf);
  788. midiEvent.data[1] = event.note_on.pitch;
  789. midiEvent.data[2] = std::max(0, std::min(127, (int)(event.note_on.velocity * 127)));
  790. midiEvent.data[3] = 0;
  791. break;
  792. case V3_EVENT_NOTE_OFF:
  793. midiEvent.size = 3;
  794. midiEvent.data[0] = 0x80 | (event.note_off.channel & 0xf);
  795. midiEvent.data[1] = event.note_off.pitch;
  796. midiEvent.data[2] = std::max(0, std::min(127, (int)(event.note_off.velocity * 127)));
  797. midiEvent.data[3] = 0;
  798. break;
  799. case V3_EVENT_POLY_PRESSURE:
  800. midiEvent.size = 3;
  801. midiEvent.data[0] = 0xA0 | (event.poly_pressure.channel & 0xf);
  802. midiEvent.data[1] = event.poly_pressure.pitch;
  803. midiEvent.data[2] = std::max(0, std::min(127, (int)(event.poly_pressure.pressure * 127)));
  804. midiEvent.data[3] = 0;
  805. break;
  806. case V3_EVENT_LEGACY_MIDI_CC_OUT:
  807. midiEvent.size = 3;
  808. midiEvent.data[0] = 0xB0 | (event.midi_cc_out.channel & 0xf);
  809. midiEvent.data[1] = event.midi_cc_out.cc_number;
  810. midiEvent.data[2] = event.midi_cc_out.value;
  811. midiEvent.data[3] = 0;
  812. // midiEvent.data[3] = event.midi_cc_out.value2; // TODO check when size should be 4
  813. break;
  814. default:
  815. midiEvent.size = 0;
  816. break;
  817. }
  818. if (midiEventCount == kMaxMidiEvents)
  819. break;
  820. }
  821. }
  822. fPlugin.run(inputs, outputs, data->nframes, fMidiEvents, midiEventCount);
  823. #else
  824. fPlugin.run(inputs, outputs, data->nframes);
  825. #endif
  826. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  827. fHostEventOutputHandle = nullptr;
  828. #endif
  829. // TODO updateParameterOutputsAndTriggers()
  830. return V3_OK;
  831. }
  832. uint32_t getTailSamples() const noexcept
  833. {
  834. return 0;
  835. }
  836. // ----------------------------------------------------------------------------------------------------------------
  837. // v3_edit_controller interface calls
  838. #if 0
  839. v3_result setComponentState(v3_bstream*, void*)
  840. {
  841. // TODO
  842. return V3_NOT_IMPLEMENTED;
  843. }
  844. v3_result setState(v3_bstream*, void*)
  845. {
  846. // TODO
  847. return V3_NOT_IMPLEMENTED;
  848. }
  849. v3_result getState(v3_bstream*, void*)
  850. {
  851. // TODO
  852. return V3_NOT_IMPLEMENTED;
  853. }
  854. #endif
  855. int32_t getParameterCount() const noexcept
  856. {
  857. return fPlugin.getParameterCount();
  858. }
  859. v3_result getParameterInfo(const int32_t index, v3_param_info* const info) const noexcept
  860. {
  861. DISTRHO_SAFE_ASSERT_RETURN(index >= 0, V3_INVALID_ARG);
  862. const uint32_t uindex = static_cast<uint32_t>(index);
  863. DISTRHO_SAFE_ASSERT_RETURN(uindex < fPlugin.getParameterCount(), V3_INVALID_ARG);
  864. // set up flags
  865. int32_t flags = 0;
  866. const auto desig = fPlugin.getParameterDesignation(index);
  867. const auto hints = fPlugin.getParameterHints(index);
  868. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  869. switch (desig)
  870. {
  871. case kParameterDesignationNull:
  872. break;
  873. case kParameterDesignationBypass:
  874. flags |= V3_PARAM_IS_BYPASS;
  875. break;
  876. }
  877. if (hints & kParameterIsAutomable)
  878. flags |= V3_PARAM_CAN_AUTOMATE;
  879. if (hints & kParameterIsOutput)
  880. flags |= V3_PARAM_READ_ONLY;
  881. // TODO V3_PARAM_IS_LIST
  882. // set up step_count
  883. int32_t step_count = 0;
  884. if (hints & kParameterIsBoolean)
  885. step_count = 1;
  886. if ((hints & kParameterIsInteger) && ranges.max - ranges.min > 1)
  887. step_count = ranges.max - ranges.min - 1;
  888. std::memset(info, 0, sizeof(v3_param_info));
  889. info->param_id = index;
  890. info->flags = flags;
  891. info->step_count = step_count;
  892. info->default_normalised_value = ranges.getNormalizedValue(ranges.def);
  893. // int32_t unit_id;
  894. strncpy_utf16(info->title, fPlugin.getParameterName(index), 128);
  895. strncpy_utf16(info->short_title, fPlugin.getParameterShortName(index), 128);
  896. strncpy_utf16(info->units, fPlugin.getParameterUnit(index), 128);
  897. return V3_OK;
  898. }
  899. v3_result getParameterStringForValue(const v3_param_id index, const double normalised, v3_str_128 output)
  900. {
  901. DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG);
  902. snprintf_f32_utf16(output, fPlugin.getParameterRanges(index).getUnnormalizedValue(normalised), 128);
  903. return V3_OK;
  904. }
  905. v3_result getParameterValueForString(const v3_param_id index, int16_t*, double*)
  906. {
  907. DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG);
  908. // TODO
  909. return V3_NOT_IMPLEMENTED;
  910. };
  911. double normalisedParameterToPlain(const v3_param_id index, const double normalised)
  912. {
  913. DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG);
  914. return fPlugin.getParameterRanges(index).getUnnormalizedValue(normalised);
  915. };
  916. double plainParameterToNormalised(const v3_param_id index, const double plain)
  917. {
  918. DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG);
  919. return fPlugin.getParameterRanges(index).getNormalizedValue(plain);
  920. };
  921. double getParameterNormalized(const v3_param_id index)
  922. {
  923. DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), 0.0);
  924. const float value = fPlugin.getParameterValue(index);
  925. return fPlugin.getParameterRanges(index).getNormalizedValue(value);
  926. }
  927. v3_result setParameterNormalized(const v3_param_id index, const double value)
  928. {
  929. DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG);
  930. const uint32_t hints = fPlugin.getParameterHints(index);
  931. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  932. float realValue = ranges.getUnnormalizedValue(value);
  933. if (hints & kParameterIsBoolean)
  934. {
  935. const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f;
  936. realValue = realValue > midRange ? ranges.max : ranges.min;
  937. }
  938. if (hints & kParameterIsInteger)
  939. {
  940. realValue = std::round(realValue);
  941. }
  942. fPlugin.setParameterValue(index, realValue);
  943. return V3_OK;
  944. }
  945. v3_result setComponentHandler(v3_component_handler* const handler, void* const arg) noexcept
  946. {
  947. fComponentHandler = handler;
  948. fComponentHandlerArg = arg;
  949. return V3_OK;
  950. }
  951. // ----------------------------------------------------------------------------------------------------------------
  952. private:
  953. // Plugin
  954. PluginExporter fPlugin;
  955. // VST3 stuff
  956. v3_component_handler* fComponentHandler;
  957. void* fComponentHandlerArg;
  958. // Temporary data
  959. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  960. MidiEvent fMidiEvents[kMaxMidiEvents];
  961. #endif
  962. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  963. v3_event_list** fHostEventOutputHandle;
  964. #endif
  965. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  966. TimePosition fTimePosition;
  967. #endif
  968. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  969. bool requestParameterValueChange(const uint32_t index, const float value)
  970. {
  971. DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false);
  972. DISTRHO_SAFE_ASSERT_RETURN(fComponentHandlerArg != nullptr, false);
  973. if (fComponentHandler->begin_edit(fComponentHandlerArg, index) != V3_OK)
  974. return false;
  975. const double normalized = fPlugin.getParameterRanges(index).getNormalizedValue(value);
  976. const bool ret = fComponentHandler->perform_edit(fComponentHandlerArg, index, normalized) == V3_OK;
  977. fComponentHandler->end_edit(fComponentHandlerArg, index);
  978. return ret;
  979. }
  980. static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
  981. {
  982. return ((PluginVst3*)ptr)->requestParameterValueChange(index, value);
  983. }
  984. #endif
  985. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  986. bool writeMidi(const MidiEvent& midiEvent)
  987. {
  988. DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fHostEventOutputHandle != nullptr, false);
  989. v3_event event;
  990. std::memset(&event, 0, sizeof(event));
  991. event.sample_offset = midiEvent.frame;
  992. const uint8_t* const data = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data;
  993. switch (data[0] & 0xf0)
  994. {
  995. case 0x80:
  996. event.type = V3_EVENT_NOTE_OFF;
  997. event.note_off.channel = data[0] & 0xf;
  998. event.note_off.pitch = data[1];
  999. event.note_off.velocity = (float)data[2] / 127.0f;
  1000. // int32_t note_id;
  1001. // float tuning;
  1002. break;
  1003. case 0x90:
  1004. event.type = V3_EVENT_NOTE_ON;
  1005. event.note_on.channel = data[0] & 0xf;
  1006. event.note_on.pitch = data[1];
  1007. // float tuning;
  1008. event.note_on.velocity = (float)data[2] / 127.0f;
  1009. // int32_t length;
  1010. // int32_t note_id;
  1011. break;
  1012. case 0xA0:
  1013. event.type = V3_EVENT_POLY_PRESSURE;
  1014. event.poly_pressure.channel = data[0] & 0xf;
  1015. event.poly_pressure.pitch = data[1];
  1016. event.poly_pressure.pressure = (float)data[2] / 127.0f;
  1017. // int32_t note_id;
  1018. break;
  1019. case 0xB0:
  1020. event.type = V3_EVENT_LEGACY_MIDI_CC_OUT;
  1021. event.midi_cc_out.channel = data[0] & 0xf;
  1022. event.midi_cc_out.cc_number = data[1];
  1023. event.midi_cc_out.value = data[2];
  1024. event.midi_cc_out.value2 = midiEvent.size == 4 ? data[3] : 0;
  1025. break;
  1026. default:
  1027. return true;
  1028. }
  1029. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1030. v3_event_list* const hostptr = (v3_event_list*)((uint8_t*)(*fHostEventOutputHandle)+sizeof(v3_funknown));
  1031. return hostptr->add_event(fHostEventOutputHandle, &event) == V3_OK;
  1032. }
  1033. static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
  1034. {
  1035. return ((PluginVst3*)ptr)->writeMidi(midiEvent);
  1036. }
  1037. #endif
  1038. };
  1039. #if DISTRHO_PLUGIN_HAS_UI
  1040. // --------------------------------------------------------------------------------------------------------------------
  1041. // dpf_plugin_view_create (called from DSP side)
  1042. v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate);
  1043. #endif
  1044. // --------------------------------------------------------------------------------------------------------------------
  1045. // dpf_edit_controller
  1046. struct v3_edit_controller_cpp : v3_funknown {
  1047. v3_plugin_base base;
  1048. v3_edit_controller controller;
  1049. };
  1050. struct dpf_edit_controller : v3_edit_controller_cpp {
  1051. std::atomic<int> refcounter;
  1052. ScopedPointer<dpf_edit_controller>* self;
  1053. ScopedPointer<PluginVst3>& vst3;
  1054. bool initialized;
  1055. dpf_edit_controller(ScopedPointer<dpf_edit_controller>* const s, ScopedPointer<PluginVst3>& v)
  1056. : refcounter(1),
  1057. self(s),
  1058. vst3(v),
  1059. initialized(false)
  1060. {
  1061. static const uint8_t* kSupportedInterfaces[] = {
  1062. v3_funknown_iid,
  1063. v3_edit_controller_iid
  1064. };
  1065. // ------------------------------------------------------------------------------------------------------------
  1066. // v3_funknown
  1067. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1068. {
  1069. d_stdout("dpf_edit_controller::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1070. *iface = NULL;
  1071. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1072. for (const uint8_t* interface_iid : kSupportedInterfaces)
  1073. {
  1074. if (v3_tuid_match(interface_iid, iid))
  1075. {
  1076. *iface = self;
  1077. return V3_OK;
  1078. }
  1079. }
  1080. return V3_NO_INTERFACE;
  1081. };
  1082. ref = []V3_API(void* self) -> uint32_t
  1083. {
  1084. d_stdout("dpf_edit_controller::ref => %p", self);
  1085. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1086. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0);
  1087. return ++controller->refcounter;
  1088. };
  1089. unref = []V3_API(void* self) -> uint32_t
  1090. {
  1091. d_stdout("dpf_edit_controller::unref => %p", self);
  1092. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1093. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0);
  1094. if (const int refcounter = --controller->refcounter)
  1095. return refcounter;
  1096. *(dpf_edit_controller**)self = nullptr;
  1097. *controller->self = nullptr;
  1098. return 0;
  1099. };
  1100. // ------------------------------------------------------------------------------------------------------------
  1101. // v3_plugin_base
  1102. base.initialise = []V3_API(void* self, struct v3_plugin_base::v3_funknown *context) -> v3_result
  1103. {
  1104. d_stdout("dpf_edit_controller::initialise => %p %p", self, context);
  1105. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1106. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1107. const bool initialized = controller->initialized;
  1108. DISTRHO_SAFE_ASSERT_RETURN(! initialized, V3_INVALID_ARG);
  1109. controller->initialized = true;
  1110. return V3_OK;
  1111. };
  1112. base.terminate = []V3_API(void* self) -> v3_result
  1113. {
  1114. d_stdout("dpf_edit_controller::terminate => %p", self);
  1115. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1116. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1117. const bool initialized = controller->initialized;
  1118. DISTRHO_SAFE_ASSERT_RETURN(initialized, V3_INVALID_ARG);
  1119. controller->initialized = false;
  1120. return V3_OK;
  1121. };
  1122. // ------------------------------------------------------------------------------------------------------------
  1123. // v3_edit_controller
  1124. controller.set_component_state = []V3_API(void* self, v3_bstream* stream) -> v3_result
  1125. {
  1126. d_stdout("dpf_edit_controller::set_component_state => %p %p", self, stream);
  1127. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1128. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1129. PluginVst3* const vst3 = controller->vst3;
  1130. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1131. #if 0
  1132. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1133. v3_bstream* const streamptr
  1134. = stream != nullptr ? (v3_bstream*)((uint8_t*)stream+sizeof(v3_funknown))
  1135. : nullptr;
  1136. return vst3->setComponentState(streamptr, stream);
  1137. #endif
  1138. return V3_NOT_IMPLEMENTED;
  1139. };
  1140. controller.set_state = []V3_API(void* self, v3_bstream* stream) -> v3_result
  1141. {
  1142. d_stdout("dpf_edit_controller::set_state => %p %p", self, stream);
  1143. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1144. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1145. PluginVst3* const vst3 = controller->vst3;
  1146. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1147. #if 0
  1148. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1149. v3_bstream* const streamptr
  1150. = stream != nullptr ? (v3_bstream*)((uint8_t*)stream+sizeof(v3_funknown))
  1151. : nullptr;
  1152. return vst3->setState(stream);
  1153. #endif
  1154. return V3_NOT_IMPLEMENTED;
  1155. };
  1156. controller.get_state = []V3_API(void* self, v3_bstream* stream) -> v3_result
  1157. {
  1158. d_stdout("dpf_edit_controller::get_state => %p %p", self, stream);
  1159. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1160. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1161. PluginVst3* const vst3 = controller->vst3;
  1162. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1163. #if 0
  1164. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1165. v3_bstream* const streamptr
  1166. = stream != nullptr ? (v3_bstream*)((uint8_t*)stream+sizeof(v3_funknown))
  1167. : nullptr;
  1168. return vst3->getState(stream);
  1169. #endif
  1170. return V3_NOT_IMPLEMENTED;
  1171. };
  1172. controller.get_parameter_count = []V3_API(void* self) -> int32_t
  1173. {
  1174. d_stdout("dpf_edit_controller::get_parameter_count => %p", self);
  1175. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1176. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1177. PluginVst3* const vst3 = controller->vst3;
  1178. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1179. return vst3->getParameterCount();
  1180. };
  1181. controller.get_parameter_info = []V3_API(void* self, int32_t param_idx, v3_param_info* param_info) -> v3_result
  1182. {
  1183. d_stdout("dpf_edit_controller::get_parameter_info => %p %i", self, param_idx);
  1184. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1185. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1186. PluginVst3* const vst3 = controller->vst3;
  1187. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1188. return vst3->getParameterInfo(param_idx, param_info);
  1189. };
  1190. controller.get_parameter_string_for_value = []V3_API(void* self, v3_param_id index, double normalised, v3_str_128 output) -> v3_result
  1191. {
  1192. d_stdout("dpf_edit_controller::get_parameter_string_for_value => %p %u %f %p", self, index, normalised, output);
  1193. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1194. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1195. PluginVst3* const vst3 = controller->vst3;
  1196. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1197. return vst3->getParameterStringForValue(index, normalised, output);
  1198. };
  1199. controller.get_parameter_value_for_string = []V3_API(void* self, v3_param_id index, int16_t* input, double* output) -> v3_result
  1200. {
  1201. d_stdout("dpf_edit_controller::get_parameter_value_for_string => %p %u %p %p", self, index, input, output);
  1202. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1203. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1204. PluginVst3* const vst3 = controller->vst3;
  1205. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1206. return vst3->getParameterValueForString(index, input, output);
  1207. };
  1208. controller.normalised_parameter_to_plain = []V3_API(void* self, v3_param_id index, double normalised) -> double
  1209. {
  1210. d_stdout("dpf_edit_controller::normalised_parameter_to_plain => %p %u %f", self, index, normalised);
  1211. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1212. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1213. PluginVst3* const vst3 = controller->vst3;
  1214. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1215. return vst3->normalisedParameterToPlain(index, normalised);
  1216. };
  1217. controller.plain_parameter_to_normalised = []V3_API(void* self, v3_param_id index, double plain) -> double
  1218. {
  1219. d_stdout("dpf_edit_controller::plain_parameter_to_normalised => %p %f", self, plain);
  1220. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1221. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1222. PluginVst3* const vst3 = controller->vst3;
  1223. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1224. return vst3->plainParameterToNormalised(index, plain);
  1225. };
  1226. controller.get_parameter_normalised = []V3_API(void* self, v3_param_id index) -> double
  1227. {
  1228. d_stdout("dpf_edit_controller::get_parameter_normalised => %p", self);
  1229. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1230. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0.0);
  1231. PluginVst3* const vst3 = controller->vst3;
  1232. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0.0);
  1233. return vst3->getParameterNormalized(index);
  1234. };
  1235. controller.set_parameter_normalised = []V3_API(void* self, v3_param_id index, double normalised) -> v3_result
  1236. {
  1237. d_stdout("dpf_edit_controller::set_parameter_normalised => %p %f", self, normalised);
  1238. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1239. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1240. PluginVst3* const vst3 = controller->vst3;
  1241. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1242. // if (dpf_plugin_view* const view = controller->view)
  1243. // {
  1244. // if (UIVst3* const uivst3 = view->uivst3)
  1245. // {
  1246. // uivst3->setParameterValueFromDSP(index, vst3->normalisedParameterToPlain(index, normalised));
  1247. // }
  1248. // }
  1249. return vst3->setParameterNormalized(index, normalised);
  1250. };
  1251. controller.set_component_handler = []V3_API(void* self, v3_component_handler** handler) -> v3_result
  1252. {
  1253. d_stdout("dpf_edit_controller::set_component_handler => %p %p", self, handler);
  1254. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1255. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  1256. PluginVst3* const vst3 = controller->vst3;
  1257. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1258. // v3_component_handler_cpp** const cpphandler = (v3_component_handler_cpp**)handler;
  1259. //
  1260. // controller->handler = cpphandler;
  1261. //
  1262. // if (controller->view != nullptr)
  1263. // {
  1264. // controller->view->handler = cpphandler;
  1265. //
  1266. // if (UIVst3* const uivst3 = controller->view->uivst3)
  1267. // uivst3->setHandler(cpphandler);
  1268. // }
  1269. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1270. v3_component_handler* const handlerptr
  1271. = handler != nullptr ? (v3_component_handler*)((uint8_t*)*(handler)+sizeof(v3_funknown))
  1272. : nullptr;
  1273. return vst3->setComponentHandler(handlerptr, handler);
  1274. };
  1275. controller.create_view = []V3_API(void* self, const char* name) -> v3_plugin_view**
  1276. {
  1277. d_stdout("dpf_edit_controller::create_view => %p %s", self, name);
  1278. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  1279. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr);
  1280. PluginVst3* const vst3 = controller->vst3;
  1281. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr);
  1282. #if DISTRHO_PLUGIN_HAS_UI
  1283. return (v3_plugin_view**)dpf_plugin_view_create(vst3->getInstancePointer(), vst3->getSampleRate());
  1284. #else
  1285. return nullptr;
  1286. #endif
  1287. };
  1288. }
  1289. };
  1290. // --------------------------------------------------------------------------------------------------------------------
  1291. // dpf_process_context_requirements
  1292. struct v3_process_context_requirements_cpp : v3_funknown {
  1293. v3_process_context_requirements req;
  1294. };
  1295. struct dpf_process_context_requirements : v3_process_context_requirements_cpp {
  1296. dpf_process_context_requirements()
  1297. {
  1298. static const uint8_t* kSupportedInterfaces[] = {
  1299. v3_funknown_iid,
  1300. v3_process_context_requirements_iid
  1301. };
  1302. // ------------------------------------------------------------------------------------------------------------
  1303. // v3_funknown
  1304. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1305. {
  1306. d_stdout("dpf_process_context_requirements::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1307. *iface = NULL;
  1308. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1309. for (const uint8_t* interface_iid : kSupportedInterfaces)
  1310. {
  1311. if (v3_tuid_match(interface_iid, iid))
  1312. {
  1313. *iface = self;
  1314. return V3_OK;
  1315. }
  1316. }
  1317. return V3_NO_INTERFACE;
  1318. };
  1319. // this is used statically, so we don't have to care here
  1320. ref = []V3_API(void*) -> uint32_t { return 1; };
  1321. unref = []V3_API(void*) -> uint32_t { return 0; };
  1322. // ------------------------------------------------------------------------------------------------------------
  1323. // v3_process_context_requirements
  1324. req.get_process_context_requirements = []V3_API(void*) -> uint32_t
  1325. {
  1326. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  1327. return 0x0
  1328. |V3_PROCESS_CTX_NEED_CONTINUOUS_TIME // V3_PROCESS_CTX_CONT_TIME_VALID
  1329. |V3_PROCESS_CTX_NEED_PROJECT_TIME // V3_PROCESS_CTX_PROJECT_TIME_VALID
  1330. |V3_PROCESS_CTX_NEED_TEMPO // V3_PROCESS_CTX_TEMPO_VALID
  1331. |V3_PROCESS_CTX_NEED_TIME_SIG // V3_PROCESS_CTX_TIME_SIG_VALID
  1332. |V3_PROCESS_CTX_NEED_TRANSPORT_STATE; // V3_PROCESS_CTX_PLAYING
  1333. #else
  1334. return 0x0;
  1335. #endif
  1336. };
  1337. }
  1338. DISTRHO_PREVENT_HEAP_ALLOCATION
  1339. };
  1340. // --------------------------------------------------------------------------------------------------------------------
  1341. // dpf_audio_processor
  1342. struct v3_audio_processor_cpp : v3_funknown {
  1343. v3_audio_processor processor;
  1344. };
  1345. struct dpf_audio_processor : v3_audio_processor_cpp {
  1346. std::atomic<int> refcounter;
  1347. ScopedPointer<dpf_audio_processor>* self;
  1348. ScopedPointer<PluginVst3>& vst3;
  1349. dpf_audio_processor(ScopedPointer<dpf_audio_processor>* const s, ScopedPointer<PluginVst3>& v)
  1350. : refcounter(1),
  1351. self(s),
  1352. vst3(v)
  1353. {
  1354. static const uint8_t* kSupportedInterfacesBase[] = {
  1355. v3_funknown_iid,
  1356. v3_audio_processor_iid
  1357. };
  1358. // ------------------------------------------------------------------------------------------------------------
  1359. // v3_funknown
  1360. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1361. {
  1362. d_stdout("dpf_audio_processor::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1363. *iface = NULL;
  1364. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1365. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  1366. {
  1367. if (v3_tuid_match(interface_iid, iid))
  1368. {
  1369. *iface = self;
  1370. return V3_OK;
  1371. }
  1372. }
  1373. if (v3_tuid_match(v3_process_context_requirements_iid, iid))
  1374. {
  1375. static dpf_process_context_requirements context_req;
  1376. static dpf_process_context_requirements* context_req_ptr = &context_req;;
  1377. *iface = &context_req_ptr;
  1378. return V3_OK;
  1379. }
  1380. return V3_NO_INTERFACE;
  1381. };
  1382. ref = []V3_API(void* self) -> uint32_t
  1383. {
  1384. d_stdout("dpf_audio_processor::ref => %p", self);
  1385. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1386. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0);
  1387. return ++processor->refcounter;
  1388. };
  1389. unref = []V3_API(void* self) -> uint32_t
  1390. {
  1391. d_stdout("dpf_audio_processor::unref => %p", self);
  1392. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1393. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0);
  1394. if (const int refcounter = --processor->refcounter)
  1395. return refcounter;
  1396. *(dpf_audio_processor**)self = nullptr;
  1397. *processor->self = nullptr;
  1398. return 0;
  1399. };
  1400. // ------------------------------------------------------------------------------------------------------------
  1401. // v3_audio_processor
  1402. processor.set_bus_arrangements = []V3_API(void* self,
  1403. v3_speaker_arrangement* inputs, int32_t num_inputs,
  1404. v3_speaker_arrangement* outputs, int32_t num_outputs) -> v3_result
  1405. {
  1406. // NOTE this is called a bunch of times
  1407. // d_stdout("dpf_audio_processor::set_bus_arrangements => %p %p %i %p %i", self, inputs, num_inputs, outputs, num_outputs);
  1408. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1409. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  1410. PluginVst3* const vst3 = processor->vst3;
  1411. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1412. return processor->vst3->setBusArrangements(inputs, num_inputs, outputs, num_outputs);
  1413. };
  1414. processor.get_bus_arrangement = []V3_API(void* self, int32_t bus_direction,
  1415. int32_t idx, v3_speaker_arrangement* arr) -> v3_result
  1416. {
  1417. d_stdout("dpf_audio_processor::get_bus_arrangement => %p %i %i %p", self, bus_direction, idx, arr);
  1418. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1419. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  1420. PluginVst3* const vst3 = processor->vst3;
  1421. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1422. return processor->vst3->getBusArrangement(bus_direction, idx, arr);
  1423. };
  1424. processor.can_process_sample_size = []V3_API(void* self, int32_t symbolic_sample_size) -> v3_result
  1425. {
  1426. d_stdout("dpf_audio_processor::can_process_sample_size => %p %i", self, symbolic_sample_size);
  1427. return symbolic_sample_size == V3_SAMPLE_32 ? V3_OK : V3_NOT_IMPLEMENTED;
  1428. };
  1429. processor.get_latency_samples = []V3_API(void* self) -> uint32_t
  1430. {
  1431. d_stdout("dpf_audio_processor::get_latency_samples => %p", self);
  1432. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1433. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0);
  1434. PluginVst3* const vst3 = processor->vst3;
  1435. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0);
  1436. return processor->vst3->getLatencySamples();
  1437. };
  1438. processor.setup_processing = []V3_API(void* self, v3_process_setup* setup) -> v3_result
  1439. {
  1440. d_stdout("dpf_audio_processor::setup_processing => %p", self);
  1441. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1442. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  1443. PluginVst3* const vst3 = processor->vst3;
  1444. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1445. d_lastBufferSize = setup->max_block_size;
  1446. d_lastSampleRate = setup->sample_rate;
  1447. return processor->vst3->setupProcessing(setup);
  1448. };
  1449. processor.set_processing = []V3_API(void* self, v3_bool state) -> v3_result
  1450. {
  1451. d_stdout("dpf_audio_processor::set_processing => %p %u", self, state);
  1452. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1453. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  1454. PluginVst3* const vst3 = processor->vst3;
  1455. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1456. return processor->vst3->setProcessing(state);
  1457. };
  1458. processor.process = []V3_API(void* self, v3_process_data* data) -> v3_result
  1459. {
  1460. // NOTE runs during RT
  1461. // d_stdout("dpf_audio_processor::process => %p", self);
  1462. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1463. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  1464. PluginVst3* const vst3 = processor->vst3;
  1465. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1466. return processor->vst3->process(data);
  1467. };
  1468. processor.get_tail_samples = []V3_API(void* self) -> uint32_t
  1469. {
  1470. d_stdout("dpf_audio_processor::get_tail_samples => %p", self);
  1471. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  1472. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0);
  1473. PluginVst3* const vst3 = processor->vst3;
  1474. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0);
  1475. return processor->vst3->getTailSamples();
  1476. };
  1477. }
  1478. };
  1479. // --------------------------------------------------------------------------------------------------------------------
  1480. // dpf_state_stream
  1481. struct v3_bstream_cpp : v3_funknown {
  1482. v3_bstream stream;
  1483. };
  1484. struct dpf_state_stream : v3_bstream_cpp {
  1485. ScopedPointer<PluginVst3>& vst3;
  1486. dpf_state_stream(ScopedPointer<PluginVst3>& v)
  1487. : vst3(v)
  1488. {
  1489. static const uint8_t* kSupportedInterfaces[] = {
  1490. v3_funknown_iid,
  1491. v3_bstream_iid
  1492. };
  1493. // ------------------------------------------------------------------------------------------------------------
  1494. // v3_funknown
  1495. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1496. {
  1497. d_stdout("dpf_factory::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1498. *iface = NULL;
  1499. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1500. for (const uint8_t* interface_iid : kSupportedInterfaces)
  1501. {
  1502. if (v3_tuid_match(interface_iid, iid))
  1503. {
  1504. *iface = self;
  1505. return V3_OK;
  1506. }
  1507. }
  1508. return V3_NO_INTERFACE;
  1509. };
  1510. // TODO
  1511. ref = []V3_API(void*) -> uint32_t { return 1; };
  1512. unref = []V3_API(void*) -> uint32_t { return 0; };
  1513. // ------------------------------------------------------------------------------------------------------------
  1514. // v3_bstream
  1515. stream.read = []V3_API(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read) -> v3_result
  1516. {
  1517. d_stdout("dpf_state_stream::read => %p %p %i %p", self, buffer, num_bytes, bytes_read);
  1518. dpf_state_stream* const stream = *(dpf_state_stream**)self;
  1519. DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED);
  1520. PluginVst3* const vst3 = stream->vst3;
  1521. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1522. return V3_NOT_IMPLEMENTED;
  1523. };
  1524. stream.write = []V3_API(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written) -> v3_result
  1525. {
  1526. d_stdout("dpf_state_stream::write => %p %p %i %p", self, buffer, num_bytes, bytes_written);
  1527. dpf_state_stream* const stream = *(dpf_state_stream**)self;
  1528. DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED);
  1529. PluginVst3* const vst3 = stream->vst3;
  1530. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1531. return V3_NOT_IMPLEMENTED;
  1532. };
  1533. stream.seek = []V3_API(void* self, int64_t pos, int32_t seek_mode, int64_t* result) -> v3_result
  1534. {
  1535. d_stdout("dpf_state_stream::seek => %p %lu %i %p", self, pos, seek_mode, result);
  1536. dpf_state_stream* const stream = *(dpf_state_stream**)self;
  1537. DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED);
  1538. PluginVst3* const vst3 = stream->vst3;
  1539. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1540. return V3_NOT_IMPLEMENTED;
  1541. };
  1542. stream.tell = []V3_API(void* self, int64_t* pos) -> v3_result
  1543. {
  1544. d_stdout("dpf_state_stream::tell => %p %p", self, pos);
  1545. dpf_state_stream* const stream = *(dpf_state_stream**)self;
  1546. DISTRHO_SAFE_ASSERT_RETURN(stream != nullptr, V3_NOT_INITIALISED);
  1547. PluginVst3* const vst3 = stream->vst3;
  1548. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1549. return V3_NOT_IMPLEMENTED;
  1550. };
  1551. }
  1552. };
  1553. // --------------------------------------------------------------------------------------------------------------------
  1554. // dpf_component
  1555. struct v3_component_cpp : v3_funknown {
  1556. v3_plugin_base base;
  1557. v3_component comp;
  1558. };
  1559. struct dpf_component : v3_component_cpp {
  1560. std::atomic<int> refcounter;
  1561. ScopedPointer<dpf_component>* self;
  1562. ScopedPointer<dpf_audio_processor> processor;
  1563. ScopedPointer<dpf_edit_controller> controller;
  1564. ScopedPointer<dpf_state_stream> stream;
  1565. ScopedPointer<PluginVst3> vst3;
  1566. dpf_component(ScopedPointer<dpf_component>* const s)
  1567. : refcounter(1),
  1568. self(s)
  1569. {
  1570. static const uint8_t* kSupportedInterfacesBase[] = {
  1571. v3_funknown_iid,
  1572. v3_plugin_base_iid,
  1573. v3_component_iid
  1574. };
  1575. // ------------------------------------------------------------------------------------------------------------
  1576. // v3_funknown
  1577. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1578. {
  1579. d_stdout("dpf_component::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1580. *iface = NULL;
  1581. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  1582. {
  1583. if (v3_tuid_match(interface_iid, iid))
  1584. {
  1585. *iface = self;
  1586. return V3_OK;
  1587. }
  1588. }
  1589. dpf_component* const component = *(dpf_component**)self;
  1590. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NO_INTERFACE);
  1591. if (v3_tuid_match(v3_audio_processor_iid, iid))
  1592. {
  1593. if (component->processor == nullptr)
  1594. component->processor = new dpf_audio_processor(&component->processor, component->vst3);
  1595. *iface = &component->processor;
  1596. return V3_OK;
  1597. }
  1598. if (v3_tuid_match(v3_edit_controller_iid, iid))
  1599. {
  1600. if (component->controller == nullptr)
  1601. component->controller = new dpf_edit_controller(&component->controller, component->vst3);
  1602. *iface = &component->controller;
  1603. return V3_OK;
  1604. }
  1605. return V3_NO_INTERFACE;
  1606. };
  1607. ref = []V3_API(void* self) -> uint32_t
  1608. {
  1609. d_stdout("dpf_component::ref => %p", self);
  1610. dpf_component* const component = *(dpf_component**)self;
  1611. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, 0);
  1612. return ++component->refcounter;
  1613. };
  1614. unref = []V3_API(void* self) -> uint32_t
  1615. {
  1616. d_stdout("dpf_component::unref => %p", self);
  1617. dpf_component* const component = *(dpf_component**)self;
  1618. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, 0);
  1619. if (const int refcounter = --component->refcounter)
  1620. return refcounter;
  1621. *(dpf_component**)self = nullptr;
  1622. *component->self = nullptr;
  1623. return 0;
  1624. };
  1625. // ------------------------------------------------------------------------------------------------------------
  1626. // v3_plugin_base
  1627. base.initialise = []V3_API(void* self, struct v3_plugin_base::v3_funknown* context) -> v3_result
  1628. {
  1629. d_stdout("dpf_component::initialise => %p %p", self, context);
  1630. dpf_component* const component = *(dpf_component**)self;
  1631. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1632. PluginVst3* const vst3 = component->vst3;
  1633. DISTRHO_SAFE_ASSERT_RETURN(vst3 == nullptr, V3_INVALID_ARG);
  1634. d_lastCanRequestParameterValueChanges = true;
  1635. // default early values
  1636. if (d_lastBufferSize == 0)
  1637. d_lastBufferSize = 2048;
  1638. if (d_lastSampleRate <= 0.0)
  1639. d_lastSampleRate = 44100.0;
  1640. component->vst3 = new PluginVst3();
  1641. return V3_OK;
  1642. };
  1643. base.terminate = []V3_API(void* self) -> v3_result
  1644. {
  1645. d_stdout("dpf_component::terminate => %p", self);
  1646. dpf_component* const component = *(dpf_component**)self;
  1647. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1648. PluginVst3* const vst3 = component->vst3;
  1649. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_INVALID_ARG);
  1650. component->vst3 = nullptr;
  1651. return V3_OK;
  1652. };
  1653. // ------------------------------------------------------------------------------------------------------------
  1654. // v3_component
  1655. comp.get_controller_class_id = []V3_API(void* self, v3_tuid class_id) -> v3_result
  1656. {
  1657. d_stdout("dpf_component::get_controller_class_id => %p %s", self, tuid2str(class_id));
  1658. dpf_component* const component = *(dpf_component**)self;
  1659. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1660. PluginVst3* const vst3 = component->vst3;
  1661. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1662. // TODO
  1663. return V3_NOT_IMPLEMENTED;
  1664. };
  1665. comp.set_io_mode = []V3_API(void* self, int32_t io_mode) -> v3_result
  1666. {
  1667. d_stdout("dpf_component::set_io_mode => %p %i", self, io_mode);
  1668. dpf_component* const component = *(dpf_component**)self;
  1669. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1670. PluginVst3* const vst3 = component->vst3;
  1671. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1672. // TODO
  1673. return V3_NOT_IMPLEMENTED;
  1674. };
  1675. comp.get_bus_count = []V3_API(void* self, int32_t media_type, int32_t bus_direction) -> int32_t
  1676. {
  1677. // NOTE runs during RT
  1678. // d_stdout("dpf_component::get_bus_count => %p %i %i", self, media_type, bus_direction);
  1679. dpf_component* const component = *(dpf_component**)self;
  1680. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1681. PluginVst3* const vst3 = component->vst3;
  1682. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1683. return vst3->getBusCount(media_type, bus_direction);
  1684. };
  1685. comp.get_bus_info = []V3_API(void* self, int32_t media_type, int32_t bus_direction,
  1686. int32_t bus_idx, v3_bus_info* info) -> v3_result
  1687. {
  1688. d_stdout("dpf_component::get_bus_info => %p %i %i %i %p", self, media_type, bus_direction, bus_idx, info);
  1689. dpf_component* const component = *(dpf_component**)self;
  1690. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1691. PluginVst3* const vst3 = component->vst3;
  1692. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1693. return vst3->getBusInfo(media_type, bus_direction, bus_idx, info);
  1694. };
  1695. comp.get_routing_info = []V3_API(void* self, v3_routing_info* input, v3_routing_info* output) -> v3_result
  1696. {
  1697. d_stdout("dpf_component::get_routing_info => %p %p %p", self, input, output);
  1698. dpf_component* const component = *(dpf_component**)self;
  1699. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1700. PluginVst3* const vst3 = component->vst3;
  1701. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1702. return vst3->getRoutingInfo(input, output);
  1703. };
  1704. comp.activate_bus = []V3_API(void* self, int32_t media_type, int32_t bus_direction,
  1705. int32_t bus_idx, v3_bool state) -> v3_result
  1706. {
  1707. // NOTE this is called a bunch of times
  1708. // d_stdout("dpf_component::activate_bus => %p %i %i %i %u", self, media_type, bus_direction, bus_idx, state);
  1709. dpf_component* const component = *(dpf_component**)self;
  1710. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1711. PluginVst3* const vst3 = component->vst3;
  1712. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1713. return vst3->activateBus(media_type, bus_direction, bus_idx, state);
  1714. };
  1715. comp.set_active = []V3_API(void* self, v3_bool state) -> v3_result
  1716. {
  1717. d_stdout("dpf_component::set_active => %p %u", self, state);
  1718. dpf_component* const component = *(dpf_component**)self;
  1719. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1720. PluginVst3* const vst3 = component->vst3;
  1721. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1722. return component->vst3->setActive(state);
  1723. };
  1724. comp.set_state = []V3_API(void* self, v3_bstream** stream) -> v3_result
  1725. {
  1726. d_stdout("dpf_component::set_state => %p", self);
  1727. dpf_component* const component = *(dpf_component**)self;
  1728. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1729. PluginVst3* const vst3 = component->vst3;
  1730. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1731. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1732. v3_bstream* const streamptr
  1733. = stream != nullptr ? (v3_bstream*)((uint8_t*)*(stream)+sizeof(v3_funknown))
  1734. : nullptr;
  1735. return vst3->setState(streamptr, stream);
  1736. };
  1737. comp.get_state = []V3_API(void* self, v3_bstream** stream) -> v3_result
  1738. {
  1739. d_stdout("dpf_component::get_state => %p %p", self, stream);
  1740. dpf_component* const component = *(dpf_component**)self;
  1741. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  1742. PluginVst3* const vst3 = component->vst3;
  1743. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  1744. // offset struct by sizeof(v3_funknown), because of differences between C and C++
  1745. v3_bstream* const streamptr
  1746. = stream != nullptr ? (v3_bstream*)((uint8_t*)*(stream)+sizeof(v3_funknown))
  1747. : nullptr;
  1748. return vst3->getState(streamptr, stream);
  1749. };
  1750. }
  1751. };
  1752. // --------------------------------------------------------------------------------------------------------------------
  1753. // dpf_factory
  1754. struct v3_plugin_factory_cpp : v3_funknown {
  1755. v3_plugin_factory v1;
  1756. v3_plugin_factory_2 v2;
  1757. v3_plugin_factory_3 v3;
  1758. };
  1759. struct dpf_factory : v3_plugin_factory_cpp {
  1760. dpf_factory()
  1761. {
  1762. static const uint8_t* kSupportedFactories[] = {
  1763. v3_funknown_iid,
  1764. v3_plugin_factory_iid,
  1765. v3_plugin_factory_2_iid,
  1766. v3_plugin_factory_3_iid
  1767. };
  1768. // ------------------------------------------------------------------------------------------------------------
  1769. // Dummy plugin to get data from
  1770. d_lastBufferSize = 512;
  1771. d_lastSampleRate = 44100.0;
  1772. d_lastCanRequestParameterValueChanges = true;
  1773. static const PluginExporter gPluginInfo(nullptr, nullptr, nullptr);
  1774. d_lastBufferSize = 0;
  1775. d_lastSampleRate = 0.0;
  1776. d_lastCanRequestParameterValueChanges = false;
  1777. dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2]
  1778. = dpf_tuid_processor[2] = dpf_tuid_view[2] = gPluginInfo.getUniqueId();
  1779. // ------------------------------------------------------------------------------------------------------------
  1780. // v3_funknown
  1781. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1782. {
  1783. d_stdout("dpf_factory::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1784. *iface = NULL;
  1785. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1786. for (const uint8_t* factory_iid : kSupportedFactories)
  1787. {
  1788. if (v3_tuid_match(factory_iid, iid))
  1789. {
  1790. *iface = self;
  1791. return V3_OK;
  1792. }
  1793. }
  1794. return V3_NO_INTERFACE;
  1795. };
  1796. // we only support 1 plugin per binary, so don't have to care here
  1797. ref = []V3_API(void*) -> uint32_t { return 1; };
  1798. unref = []V3_API(void*) -> uint32_t { return 0; };
  1799. // ------------------------------------------------------------------------------------------------------------
  1800. // v3_plugin_factory
  1801. v1.get_factory_info = []V3_API(void*, struct v3_factory_info* const info) -> v3_result
  1802. {
  1803. std::memset(info, 0, sizeof(*info));
  1804. DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo.getMaker(), sizeof(info->vendor));
  1805. DISTRHO_NAMESPACE::strncpy(info->url, gPluginInfo.getHomePage(), sizeof(info->url));
  1806. // DISTRHO_NAMESPACE::strncpy(info->email, "", sizeof(info->email)); // TODO
  1807. return V3_OK;
  1808. };
  1809. v1.num_classes = []V3_API(void*) -> int32_t
  1810. {
  1811. return 1;
  1812. };
  1813. v1.get_class_info = []V3_API(void*, int32_t idx, struct v3_class_info* const info) -> v3_result
  1814. {
  1815. std::memset(info, 0, sizeof(*info));
  1816. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  1817. std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  1818. info->cardinality = 0x7FFFFFFF;
  1819. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
  1820. DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo.getName(), sizeof(info->name));
  1821. return V3_OK;
  1822. };
  1823. v1.create_instance = []V3_API(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance) -> v3_result
  1824. {
  1825. d_stdout("dpf_factory::create_instance => %p %s %s %p", self, tuid2str(class_id), tuid2str(iid), instance);
  1826. DISTRHO_SAFE_ASSERT_RETURN(v3_tuid_match(class_id, *(v3_tuid*)&dpf_tuid_class) &&
  1827. v3_tuid_match(iid, v3_component_iid), V3_NO_INTERFACE);
  1828. dpf_factory* const factory = *(dpf_factory**)self;
  1829. DISTRHO_SAFE_ASSERT_RETURN(factory != nullptr, V3_NOT_INITIALISED);
  1830. ScopedPointer<dpf_component>* const componentptr = new ScopedPointer<dpf_component>;
  1831. *componentptr = new dpf_component(componentptr);
  1832. *instance = componentptr;
  1833. return V3_OK;
  1834. };
  1835. // ------------------------------------------------------------------------------------------------------------
  1836. // v3_plugin_factory_2
  1837. v2.get_class_info_2 = []V3_API(void*, int32_t idx, struct v3_class_info_2* info) -> v3_result
  1838. {
  1839. std::memset(info, 0, sizeof(*info));
  1840. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  1841. std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  1842. info->cardinality = 0x7FFFFFFF;
  1843. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category));
  1844. DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo.getName(), ARRAY_SIZE(info->name));
  1845. info->class_flags = 0;
  1846. // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO
  1847. DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo.getMaker(), ARRAY_SIZE(info->vendor));
  1848. DISTRHO_NAMESPACE::snprintf_u32(info->version, gPluginInfo.getVersion(), ARRAY_SIZE(info->version));
  1849. DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ?
  1850. return V3_OK;
  1851. };
  1852. // ------------------------------------------------------------------------------------------------------------
  1853. // v3_plugin_factory_3
  1854. v3.get_class_info_utf16 = []V3_API(void*, int32_t idx, struct v3_class_info_3* info) -> v3_result
  1855. {
  1856. std::memset(info, 0, sizeof(*info));
  1857. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  1858. std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  1859. info->cardinality = 0x7FFFFFFF;
  1860. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category));
  1861. DISTRHO_NAMESPACE::strncpy_utf16(info->name, gPluginInfo.getName(), ARRAY_SIZE(info->name));
  1862. info->class_flags = 0;
  1863. // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", ARRAY_SIZE(info->sub_categories)); // TODO
  1864. DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, gPluginInfo.getMaker(), sizeof(info->vendor));
  1865. DISTRHO_NAMESPACE::snprintf_u32_utf16(info->version, gPluginInfo.getVersion(), ARRAY_SIZE(info->version));
  1866. DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ?
  1867. return V3_OK;
  1868. };
  1869. v3.set_host_context = []V3_API (void* self, struct v3_funknown* host) -> v3_result
  1870. {
  1871. d_stdout("dpf_factory::set_host_context => %p %p", self, host);
  1872. return V3_NOT_IMPLEMENTED;
  1873. };
  1874. }
  1875. DISTRHO_PREVENT_HEAP_ALLOCATION
  1876. };
  1877. END_NAMESPACE_DISTRHO
  1878. // --------------------------------------------------------------------------------------------------------------------
  1879. // VST3 entry point
  1880. DISTRHO_PLUGIN_EXPORT
  1881. const void* GetPluginFactory(void);
  1882. const void* GetPluginFactory(void)
  1883. {
  1884. USE_NAMESPACE_DISTRHO;
  1885. static const dpf_factory factory;
  1886. static const v3_funknown* const factoryptr = &factory;
  1887. return &factoryptr;
  1888. }
  1889. // --------------------------------------------------------------------------------------------------------------------
  1890. // OS specific module load
  1891. #if defined(DISTRHO_OS_MAC)
  1892. # define ENTRYFNNAME bundleEntry
  1893. # define EXITFNNAME bundleExit
  1894. #elif defined(DISTRHO_OS_WINDOWS)
  1895. # define ENTRYFNNAME InitDll
  1896. # define EXITFNNAME ExitDll
  1897. #else
  1898. # define ENTRYFNNAME ModuleEntry
  1899. # define EXITFNNAME ModuleExit
  1900. #endif
  1901. DISTRHO_PLUGIN_EXPORT
  1902. bool ENTRYFNNAME(void*);
  1903. bool ENTRYFNNAME(void*)
  1904. {
  1905. return true;
  1906. }
  1907. DISTRHO_PLUGIN_EXPORT
  1908. bool EXITFNNAME(void);
  1909. bool EXITFNNAME(void)
  1910. {
  1911. return true;
  1912. }
  1913. #undef ENTRYFNNAME
  1914. #undef EXITFNNAME
  1915. // --------------------------------------------------------------------------------------------------------------------