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.

2437 lines
90KB

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