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.

3620 lines
132KB

  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. #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
  19. # undef DISTRHO_PLUGIN_HAS_UI
  20. # define DISTRHO_PLUGIN_HAS_UI 0
  21. #endif
  22. #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  23. # undef DISTRHO_PLUGIN_HAS_UI
  24. # define DISTRHO_PLUGIN_HAS_UI 0
  25. #endif
  26. #if DISTRHO_PLUGIN_HAS_UI
  27. # include "../extra/RingBuffer.hpp"
  28. #endif
  29. #include "travesty/audio_processor.h"
  30. #include "travesty/component.h"
  31. #include "travesty/edit_controller.h"
  32. #include "travesty/factory.h"
  33. #include "travesty/message.h"
  34. #include <atomic>
  35. #include <map>
  36. #include <string>
  37. #include <vector>
  38. /* TODO items:
  39. * - base component refcount handling
  40. * - parameter enumeration as lists
  41. * - hide parameter outputs?
  42. * - hide program parameter?
  43. * - deal with parameter triggers
  44. * - midi cc parameter mapping
  45. * - full MIDI1 encode and decode
  46. * - decode version number (0x010203 -> 1.2.3)
  47. * - bus arrangements
  48. * - optional audio buses, create dummy buffer of max_block_size length for them
  49. * - routing info, do we care?
  50. * - set sidechain bus name from port group
  51. * - implement getParameterValueForString (use names from enumeration if available, fallback to std::atof)
  52. * - set factory class_flags
  53. * - set factory sub_categories
  54. * - set factory email (needs new DPF API, useful for LV2 as well)
  55. * - do something with get_controller_class_id and set_io_mode?
  56. * - replace dpf_message_create with host-side message creation
  57. */
  58. START_NAMESPACE_DISTRHO
  59. // --------------------------------------------------------------------------------------------------------------------
  60. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  61. static constexpr const writeMidiFunc writeMidiCallback = nullptr;
  62. #endif
  63. #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  64. static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
  65. #endif
  66. typedef std::map<const String, String> StringMap;
  67. // --------------------------------------------------------------------------------------------------------------------
  68. // custom v3_tuid compatible type
  69. typedef uint32_t dpf_tuid[4];
  70. static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch");
  71. // --------------------------------------------------------------------------------------------------------------------
  72. // custom, constant uids related to DPF
  73. static constexpr const uint32_t dpf_id_entry = d_cconst('D', 'P', 'F', ' ');
  74. static constexpr const uint32_t dpf_id_clas = d_cconst('c', 'l', 'a', 's');
  75. static constexpr const uint32_t dpf_id_comp = d_cconst('c', 'o', 'm', 'p');
  76. static constexpr const uint32_t dpf_id_ctrl = d_cconst('c', 't', 'r', 'l');
  77. static constexpr const uint32_t dpf_id_proc = d_cconst('p', 'r', 'o', 'c');
  78. static constexpr const uint32_t dpf_id_view = d_cconst('v', 'i', 'e', 'w');
  79. // --------------------------------------------------------------------------------------------------------------------
  80. // plugin specific uids (values are filled in during plugin init)
  81. static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, 0 };
  82. static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, 0 };
  83. static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, 0 };
  84. static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, 0 };
  85. static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 };
  86. // --------------------------------------------------------------------------------------------------------------------
  87. // custom attribute list struct, used for sending utf8 strings
  88. struct v3_attribute_list_utf8 {
  89. struct v3_funknown;
  90. v3_result (V3_API *set_string_utf8)(void* self, const char* id, const char* string);
  91. v3_result (V3_API *get_string_utf8)(void* self, const char* id, char* string, uint32_t size);
  92. };
  93. static constexpr const v3_tuid v3_attribute_list_utf8_iid =
  94. V3_ID(d_cconst('D','P','F',' '),
  95. d_cconst('c','l','a','s'),
  96. d_cconst('a','t','t','r'),
  97. d_cconst('u','t','f','8'));
  98. // --------------------------------------------------------------------------------------------------------------------
  99. // Utility functions
  100. const char* tuid2str(const v3_tuid iid)
  101. {
  102. static constexpr const struct {
  103. v3_tuid iid;
  104. const char* name;
  105. } extra_known_iids[] = {
  106. { V3_ID(0x00000000,0x00000000,0x00000000,0x00000000), "(nil)" },
  107. // edit-controller
  108. { V3_ID(0xF040B4B3,0xA36045EC,0xABCDC045,0xB4D5A2CC), "{v3_component_handler2|NOT}" },
  109. { V3_ID(0x7F4EFE59,0xF3204967,0xAC27A3AE,0xAFB63038), "{v3_edit_controller2|NOT}" },
  110. { V3_ID(0x067D02C1,0x5B4E274D,0xA92D90FD,0x6EAF7240), "{v3_component_handler_bus_activation|NOT}" },
  111. { V3_ID(0xDF0FF9F7,0x49B74669,0xB63AB732,0x7ADBF5E5), "{v3_midi_mapping|NOT}" },
  112. { V3_ID(0xC1271208,0x70594098,0xB9DD34B3,0x6BB0195E), "{v3_edit_controller_host_editing|NOT}" },
  113. // units
  114. { V3_ID(0x8683B01F,0x7B354F70,0xA2651DEC,0x353AF4FF), "{v3_program_list_data|NOT}" },
  115. { V3_ID(0x6C389611,0xD391455D,0xB870B833,0x94A0EFDD), "{v3_unit_data|NOT}" },
  116. { V3_ID(0x4B5147F8,0x4654486B,0x8DAB30BA,0x163A3C56), "{v3_unit_handler|NOT}" },
  117. { V3_ID(0xF89F8CDF,0x699E4BA5,0x96AAC9A4,0x81452B01), "{v3_unit_handler2|NOT}" },
  118. { V3_ID(0x3D4BD6B5,0x913A4FD2,0xA886E768,0xA5EB92C1), "{v3_unit_info|NOT}" },
  119. // misc
  120. { V3_ID(0x0F194781,0x8D984ADA,0xBBA0C1EF,0xC011D8D0), "{v3_info_listener|NOT}" },
  121. };
  122. if (v3_tuid_match(iid, v3_audio_processor_iid))
  123. return "{v3_audio_processor}";
  124. if (v3_tuid_match(iid, v3_attribute_list_iid))
  125. return "{v3_attribute_list_iid}";
  126. if (v3_tuid_match(iid, v3_attribute_list_utf8_iid))
  127. return "{v3_attribute_list_utf8_iid|CUSTOM}";
  128. if (v3_tuid_match(iid, v3_bstream_iid))
  129. return "{v3_bstream}";
  130. if (v3_tuid_match(iid, v3_component_iid))
  131. return "{v3_component}";
  132. if (v3_tuid_match(iid, v3_component_handler_iid))
  133. return "{v3_component_handler}";
  134. if (v3_tuid_match(iid, v3_connection_point_iid))
  135. return "{v3_connection_point_iid}";
  136. if (v3_tuid_match(iid, v3_edit_controller_iid))
  137. return "{v3_edit_controller}";
  138. if (v3_tuid_match(iid, v3_event_list_iid))
  139. return "{v3_event_list}";
  140. if (v3_tuid_match(iid, v3_funknown_iid))
  141. return "{v3_funknown}";
  142. if (v3_tuid_match(iid, v3_message_iid))
  143. return "{v3_message_iid}";
  144. if (v3_tuid_match(iid, v3_param_value_queue_iid))
  145. return "{v3_param_value_queue}";
  146. if (v3_tuid_match(iid, v3_param_changes_iid))
  147. return "{v3_param_changes}";
  148. if (v3_tuid_match(iid, v3_plugin_base_iid))
  149. return "{v3_plugin_base}";
  150. if (v3_tuid_match(iid, v3_plugin_factory_iid))
  151. return "{v3_plugin_factory}";
  152. if (v3_tuid_match(iid, v3_plugin_factory_2_iid))
  153. return "{v3_plugin_factory_2}";
  154. if (v3_tuid_match(iid, v3_plugin_factory_3_iid))
  155. return "{v3_plugin_factory_3}";
  156. if (v3_tuid_match(iid, v3_plugin_frame_iid))
  157. return "{v3_plugin_frame}";
  158. if (v3_tuid_match(iid, v3_plugin_view_iid))
  159. return "{v3_plugin_view}";
  160. if (v3_tuid_match(iid, v3_plugin_view_content_scale_iid))
  161. return "{v3_plugin_view_content_scale_iid}";
  162. if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid))
  163. return "{v3_plugin_view_parameter_finder}";
  164. if (v3_tuid_match(iid, v3_process_context_requirements_iid))
  165. return "{v3_process_context_requirements}";
  166. if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0)
  167. return "{dpf_tuid_class}";
  168. if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0)
  169. return "{dpf_tuid_component}";
  170. if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0)
  171. return "{dpf_tuid_controller}";
  172. if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0)
  173. return "{dpf_tuid_processor}";
  174. if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0)
  175. return "{dpf_tuid_view}";
  176. for (size_t i=0; i<ARRAY_SIZE(extra_known_iids); ++i)
  177. {
  178. if (v3_tuid_match(iid, extra_known_iids[i].iid))
  179. return extra_known_iids[i].name;
  180. }
  181. static char buf[46];
  182. std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}",
  183. (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
  184. (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]),
  185. (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]),
  186. (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15]));
  187. return buf;
  188. }
  189. // --------------------------------------------------------------------------------------------------------------------
  190. static void strncpy(char* const dst, const char* const src, const size_t length)
  191. {
  192. DISTRHO_SAFE_ASSERT_RETURN(length > 0,);
  193. if (const size_t len = std::min(std::strlen(src), length-1U))
  194. {
  195. std::memcpy(dst, src, len);
  196. dst[len] = '\0';
  197. }
  198. else
  199. {
  200. dst[0] = '\0';
  201. }
  202. }
  203. void strncpy_utf16(int16_t* const dst, const char* const src, const size_t length)
  204. {
  205. DISTRHO_SAFE_ASSERT_RETURN(length > 0,);
  206. if (const size_t len = std::min(std::strlen(src), length-1U))
  207. {
  208. for (size_t i=0; i<len; ++i)
  209. {
  210. // skip non-ascii chars
  211. if ((uint8_t)src[i] >= 0x80)
  212. continue;
  213. dst[i] = src[i];
  214. }
  215. dst[len] = 0;
  216. }
  217. else
  218. {
  219. dst[0] = 0;
  220. }
  221. }
  222. // --------------------------------------------------------------------------------------------------------------------
  223. template<typename T, const char* const format>
  224. static void snprintf_t(char* const dst, const T value, const size_t size)
  225. {
  226. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  227. std::snprintf(dst, size-1, format, value);
  228. dst[size-1] = '\0';
  229. }
  230. template<typename T, const char* const format>
  231. static void snprintf_utf16_t(int16_t* const dst, const T value, const size_t size)
  232. {
  233. DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
  234. char* const tmpbuf = (char*)std::malloc(size);
  235. DISTRHO_SAFE_ASSERT_RETURN(tmpbuf != nullptr,);
  236. std::snprintf(tmpbuf, size-1, format, value);
  237. tmpbuf[size-1] = '\0';
  238. strncpy_utf16(dst, tmpbuf, size);
  239. std::free(tmpbuf);
  240. }
  241. static constexpr const char format_i32[] = "%d";
  242. static constexpr const char format_f32[] = "%f";
  243. static constexpr const char format_u32[] = "%u";
  244. static constexpr void (*const snprintf_u32)(char*, uint32_t, size_t) = snprintf_t<uint32_t, format_u32>;
  245. static constexpr void (*const snprintf_f32_utf16)(int16_t*, float, size_t) = snprintf_utf16_t<float, format_f32>;
  246. static constexpr void (*const snprintf_u32_utf16)(int16_t*, uint32_t, size_t) = snprintf_utf16_t<uint32_t, format_u32>;
  247. // --------------------------------------------------------------------------------------------------------------------
  248. // create message object (implementation comes later)
  249. v3_message** dpf_message_create(const char* id);
  250. // --------------------------------------------------------------------------------------------------------------------
  251. // dpf_plugin_view_create (implemented on UI side)
  252. v3_plugin_view** dpf_plugin_view_create(void* instancePointer, double sampleRate);
  253. // --------------------------------------------------------------------------------------------------------------------
  254. /**
  255. * VST3 DSP class.
  256. *
  257. * All the dynamic things from VST3 get implemented here, free of complex low-level VST3 pointer things.
  258. * The DSP is created during the "initialise" component event, and destroyed during "terminate".
  259. *
  260. * The low-level VST3 stuff comes after.
  261. */
  262. class PluginVst3
  263. {
  264. /* buses: we provide 1 for the main audio (if there is any) plus 1 for each sidechain or cv port.
  265. * Main audio comes first, if available.
  266. * Then sidechain, also if available.
  267. * And finally each CV port individually.
  268. *
  269. * MIDI will have a single bus, nothing special there.
  270. */
  271. struct BusInfo {
  272. uint8_t audio = 0; // either 0 or 1
  273. uint8_t sidechain = 0; // either 0 or 1
  274. uint32_t numMainAudio = 0;
  275. uint32_t numSidechain = 0;
  276. uint32_t numCV = 0;
  277. } inputBuses, outputBuses;
  278. public:
  279. PluginVst3()
  280. : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback),
  281. fComponentHandler(nullptr),
  282. #if DISTRHO_PLUGIN_HAS_UI
  283. fConnection(nullptr),
  284. #endif
  285. fParameterOffset(fPlugin.getParameterOffset()),
  286. fRealParameterCount(fParameterOffset + fPlugin.getParameterCount()),
  287. fParameterValues(nullptr),
  288. fChangedParameterValues(nullptr)
  289. #if DISTRHO_PLUGIN_HAS_UI
  290. , fConnectedToUI(false)
  291. , fNextSampleRate(0.0)
  292. #endif
  293. #if DISTRHO_PLUGIN_WANT_LATENCY
  294. , fLastKnownLatency(fPlugin.getLatency())
  295. #endif
  296. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  297. , fHostEventOutputHandle(nullptr)
  298. #endif
  299. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  300. , fCurrentProgram(0)
  301. , fProgramCountMinusOne(fPlugin.getProgramCount()-1)
  302. #endif
  303. {
  304. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  305. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  306. {
  307. const uint32_t hints = fPlugin.getAudioPortHints(true, i);
  308. if (hints & kAudioPortIsCV)
  309. ++inputBuses.numCV;
  310. else
  311. ++inputBuses.numMainAudio;
  312. if (hints & kAudioPortIsSidechain)
  313. ++inputBuses.numSidechain;
  314. }
  315. if (inputBuses.numMainAudio != 0)
  316. inputBuses.audio = 1;
  317. if (inputBuses.numSidechain != 0)
  318. inputBuses.sidechain = 1;
  319. uint32_t cvInputBusId = 0;
  320. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  321. {
  322. AudioPortWithBusId& port(fPlugin.getAudioPort(true, i));
  323. if (port.hints & kAudioPortIsCV)
  324. port.busId = inputBuses.audio + inputBuses.sidechain + cvInputBusId++;
  325. else if (port.hints & kAudioPortIsSidechain)
  326. port.busId = 1;
  327. else
  328. port.busId = 0;
  329. }
  330. #endif
  331. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  332. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  333. {
  334. const uint32_t hints = fPlugin.getAudioPortHints(false, i);
  335. if (hints & kAudioPortIsCV)
  336. ++outputBuses.numCV;
  337. else
  338. ++outputBuses.numMainAudio;
  339. if (hints & kAudioPortIsSidechain)
  340. ++outputBuses.numSidechain;
  341. }
  342. if (outputBuses.numMainAudio != 0)
  343. outputBuses.audio = 1;
  344. if (outputBuses.numSidechain != 0)
  345. outputBuses.sidechain = 1;
  346. uint32_t cvOutputBusId = 0;
  347. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  348. {
  349. AudioPortWithBusId& port(fPlugin.getAudioPort(false, i));
  350. if (port.hints & kAudioPortIsCV)
  351. port.busId = outputBuses.audio + outputBuses.sidechain + cvOutputBusId++;
  352. else if (port.hints & kAudioPortIsSidechain)
  353. port.busId = 1;
  354. else
  355. port.busId = 0;
  356. }
  357. #endif
  358. if (const uint32_t parameterCount = fPlugin.getParameterCount())
  359. {
  360. fParameterValues = new float[parameterCount];
  361. for (uint32_t i=0; i < parameterCount; ++i)
  362. fParameterValues[i] = fPlugin.getParameterDefault(i);
  363. }
  364. if (fRealParameterCount != 0)
  365. {
  366. fChangedParameterValues = new bool[fRealParameterCount];
  367. std::memset(fChangedParameterValues, 0, sizeof(bool)*fRealParameterCount);
  368. }
  369. #if DISTRHO_PLUGIN_WANT_STATE
  370. for (uint32_t i=0, count=fPlugin.getStateCount(); i<count; ++i)
  371. {
  372. const String& dkey(fPlugin.getStateKey(i));
  373. fStateMap[dkey] = fPlugin.getStateDefaultValue(i);
  374. }
  375. #endif
  376. }
  377. ~PluginVst3()
  378. {
  379. if (fParameterValues != nullptr)
  380. {
  381. delete[] fParameterValues;
  382. fParameterValues = nullptr;
  383. }
  384. if (fChangedParameterValues != nullptr)
  385. {
  386. delete[] fChangedParameterValues;
  387. fChangedParameterValues = nullptr;
  388. }
  389. }
  390. // ----------------------------------------------------------------------------------------------------------------
  391. // stuff called for UI creation
  392. void* getInstancePointer() const noexcept
  393. {
  394. return fPlugin.getInstancePointer();
  395. }
  396. double getSampleRate() const noexcept
  397. {
  398. return fPlugin.getSampleRate();
  399. }
  400. // ----------------------------------------------------------------------------------------------------------------
  401. // v3_component interface calls
  402. int32_t getBusCount(const int32_t mediaType, const int32_t busDirection) const noexcept
  403. {
  404. switch (mediaType)
  405. {
  406. case V3_AUDIO:
  407. if (busDirection == V3_INPUT)
  408. return inputBuses.audio + inputBuses.sidechain + inputBuses.numCV;
  409. if (busDirection == V3_OUTPUT)
  410. return outputBuses.audio + outputBuses.sidechain + outputBuses.numCV;
  411. break;
  412. case V3_EVENT:
  413. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  414. if (busDirection == V3_INPUT)
  415. return 1;
  416. #endif
  417. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  418. if (busDirection == V3_OUTPUT)
  419. return 1;
  420. #endif
  421. break;
  422. }
  423. return 0;
  424. }
  425. v3_result getBusInfo(const int32_t mediaType,
  426. const int32_t busDirection,
  427. const int32_t busIndex,
  428. v3_bus_info* const info) const
  429. {
  430. DISTRHO_SAFE_ASSERT_INT_RETURN(mediaType == V3_AUDIO || mediaType == V3_EVENT, mediaType, V3_INVALID_ARG);
  431. DISTRHO_SAFE_ASSERT_INT_RETURN(busDirection == V3_INPUT || busDirection == V3_OUTPUT, busDirection, V3_INVALID_ARG);
  432. DISTRHO_SAFE_ASSERT_INT_RETURN(busIndex >= 0, busIndex, V3_INVALID_ARG);
  433. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 || DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  434. const uint32_t busId = static_cast<uint32_t>(busIndex);
  435. #endif
  436. if (mediaType == V3_AUDIO)
  437. {
  438. #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  439. int32_t numChannels;
  440. v3_bus_flags flags;
  441. v3_bus_types busType;
  442. v3_str_128 busName = {};
  443. if (busDirection == V3_INPUT)
  444. {
  445. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  446. switch (busId)
  447. {
  448. case 0:
  449. if (inputBuses.audio)
  450. {
  451. numChannels = inputBuses.numMainAudio;
  452. busType = V3_MAIN;
  453. flags = V3_DEFAULT_ACTIVE;
  454. break;
  455. }
  456. // fall-through
  457. case 1:
  458. if (inputBuses.sidechain)
  459. {
  460. numChannels = inputBuses.numSidechain;
  461. busType = V3_AUX;
  462. flags = v3_bus_flags(0);
  463. break;
  464. }
  465. // fall-through
  466. default:
  467. numChannels = 1;
  468. busType = V3_AUX;
  469. flags = V3_IS_CONTROL_VOLTAGE;
  470. break;
  471. }
  472. if (busType == V3_MAIN)
  473. {
  474. strncpy_utf16(busName, "Audio Input", 128);
  475. }
  476. else
  477. {
  478. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  479. {
  480. const AudioPortWithBusId& port(fPlugin.getAudioPort(true, i));
  481. // TODO find port group name for sidechain buses
  482. if (port.busId == busId)
  483. {
  484. strncpy_utf16(busName, port.name, 128);
  485. break;
  486. }
  487. }
  488. }
  489. #else
  490. return V3_INVALID_ARG;
  491. #endif // DISTRHO_PLUGIN_NUM_INPUTS
  492. }
  493. else
  494. {
  495. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  496. switch (busId)
  497. {
  498. case 0:
  499. if (outputBuses.audio)
  500. {
  501. numChannels = outputBuses.numMainAudio;
  502. busType = V3_MAIN;
  503. flags = V3_DEFAULT_ACTIVE;
  504. break;
  505. }
  506. // fall-through
  507. case 1:
  508. if (outputBuses.sidechain)
  509. {
  510. numChannels = outputBuses.numSidechain;
  511. busType = V3_AUX;
  512. flags = v3_bus_flags(0);
  513. break;
  514. }
  515. // fall-through
  516. default:
  517. numChannels = 1;
  518. busType = V3_AUX;
  519. flags = V3_IS_CONTROL_VOLTAGE;
  520. break;
  521. }
  522. if (busType == V3_MAIN)
  523. {
  524. strncpy_utf16(busName, "Audio Output", 128);
  525. }
  526. else
  527. {
  528. for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  529. {
  530. const AudioPortWithBusId& port(fPlugin.getAudioPort(false, i));
  531. // TODO find port group name for sidechain buses
  532. if (port.busId == busId)
  533. {
  534. strncpy_utf16(busName, port.name, 128);
  535. break;
  536. }
  537. }
  538. }
  539. #else
  540. return V3_INVALID_ARG;
  541. #endif // DISTRHO_PLUGIN_NUM_OUTPUTS
  542. }
  543. std::memset(info, 0, sizeof(v3_bus_info));
  544. info->media_type = V3_AUDIO;
  545. info->direction = busDirection;
  546. info->channel_count = numChannels;
  547. std::memcpy(info->bus_name, busName, sizeof(busName));
  548. info->bus_type = busType;
  549. info->flags = flags;
  550. return V3_OK;
  551. #else
  552. return V3_INVALID_ARG;
  553. #endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS
  554. }
  555. else
  556. {
  557. if (busDirection == V3_INPUT)
  558. {
  559. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  560. DISTRHO_SAFE_ASSERT_RETURN(busId == 0, V3_INVALID_ARG);
  561. #else
  562. return V3_INVALID_ARG;
  563. #endif
  564. }
  565. else
  566. {
  567. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  568. DISTRHO_SAFE_ASSERT_RETURN(busId == 0, V3_INVALID_ARG);
  569. #else
  570. return V3_INVALID_ARG;
  571. #endif
  572. }
  573. info->media_type = V3_EVENT;
  574. info->direction = busDirection;
  575. info->channel_count = 1;
  576. strncpy_utf16(info->bus_name, busDirection == V3_INPUT ? "Event/MIDI Input"
  577. : "Event/MIDI Output", 128);
  578. info->bus_type = V3_MAIN;
  579. info->flags = V3_DEFAULT_ACTIVE;
  580. return V3_OK;
  581. }
  582. }
  583. v3_result getRoutingInfo(v3_routing_info*, v3_routing_info*)
  584. {
  585. // TODO
  586. return V3_NOT_IMPLEMENTED;
  587. }
  588. v3_result activateBus(const int32_t /* mediaType */,
  589. const int32_t /* busDirection */,
  590. const int32_t /* busIndex */,
  591. const bool /* state */)
  592. {
  593. // TODO, returning ok to make bitwig happy
  594. return V3_OK;
  595. }
  596. v3_result setActive(const bool active)
  597. {
  598. if (active)
  599. fPlugin.activate();
  600. else
  601. fPlugin.deactivateIfNeeded();
  602. return V3_OK;
  603. }
  604. /* state: we pack pairs of key-value strings each separated by a null/zero byte.
  605. * current-program comes first, then dpf key/value states and then parameters.
  606. * parameters are simply converted to/from strings and floats.
  607. * the parameter symbol is used as the "key", so it is possible to reorder them or even remove and add safely.
  608. * there are markers for begin and end of state and parameters, so they never conflict.
  609. */
  610. v3_result setState(v3_bstream** const stream)
  611. {
  612. #if DISTRHO_PLUGIN_HAS_UI
  613. const bool connectedToUI = fConnection != nullptr && fConnectedToUI;
  614. #endif
  615. const uint32_t paramCount = fPlugin.getParameterCount();
  616. String key, value;
  617. bool fillingKey = true; // if filling key or value
  618. char queryingType = 'i'; // can be 'n', 's' or 'p' (none, states, parameters)
  619. char buffer[512], orig;
  620. buffer[sizeof(buffer)-1] = '\xff';
  621. v3_result res;
  622. for (int32_t pos = 0, term = 0, read; term == 0; pos += read)
  623. {
  624. res = v3_cpp_obj(stream)->read(stream, buffer, sizeof(buffer)-1, &read);
  625. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  626. DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR);
  627. for (int32_t i = 0; i < read; ++i)
  628. {
  629. // found terminator, stop here
  630. if (buffer[i] == '\xfe')
  631. {
  632. term = 1;
  633. break;
  634. }
  635. // store character at read position
  636. orig = buffer[read];
  637. // place null character to create valid string
  638. buffer[read] = '\0';
  639. // append to temporary vars
  640. if (fillingKey)
  641. key += buffer + i;
  642. else
  643. value += buffer + i;
  644. // increase buffer offset by length of string
  645. i += std::strlen(buffer + i);
  646. // restore read character
  647. buffer[read] = orig;
  648. // if buffer offset points to null, we found the end of a string, lets check
  649. if (buffer[i] == '\0')
  650. {
  651. // special keys
  652. if (key == "__dpf_state_begin__")
  653. {
  654. DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'i' || queryingType == 'n',
  655. queryingType, V3_INTERNAL_ERR);
  656. queryingType = 's';
  657. key.clear();
  658. value.clear();
  659. continue;
  660. }
  661. if (key == "__dpf_state_end__")
  662. {
  663. DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 's', queryingType, V3_INTERNAL_ERR);
  664. queryingType = 'n';
  665. key.clear();
  666. value.clear();
  667. continue;
  668. }
  669. if (key == "__dpf_parameters_begin__")
  670. {
  671. DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'i' || queryingType == 'n',
  672. queryingType, V3_INTERNAL_ERR);
  673. queryingType = 'p';
  674. key.clear();
  675. value.clear();
  676. continue;
  677. }
  678. if (key == "__dpf_parameters_end__")
  679. {
  680. DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'p', queryingType, V3_INTERNAL_ERR);
  681. queryingType = 'x';
  682. key.clear();
  683. value.clear();
  684. continue;
  685. }
  686. // no special key, swap between reading real key and value
  687. fillingKey = !fillingKey;
  688. // if there is no value yet keep reading until we have one (TODO check empty values on purpose)
  689. if (value.isEmpty())
  690. continue;
  691. if (key == "__dpf_program__")
  692. {
  693. DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'i', queryingType, V3_INTERNAL_ERR);
  694. queryingType = 'n';
  695. d_stdout("found program '%s'", value.buffer());
  696. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  697. const int program = std::atoi(value.buffer());
  698. DISTRHO_SAFE_ASSERT_CONTINUE(program >= 0);
  699. fCurrentProgram = static_cast<uint32_t>(program);
  700. fPlugin.loadProgram(fCurrentProgram);
  701. # if DISTRHO_PLUGIN_HAS_UI
  702. if (connectedToUI)
  703. {
  704. fChangedParameterValues[0] = false;
  705. sendParameterChangeToUI(0, fCurrentProgram);
  706. }
  707. # endif
  708. #endif
  709. }
  710. else if (queryingType == 's')
  711. {
  712. d_stdout("found state '%s' '%s'", key.buffer(), value.buffer());
  713. #if DISTRHO_PLUGIN_WANT_STATE
  714. if (fPlugin.wantStateKey(key))
  715. {
  716. fStateMap[key] = value;
  717. fPlugin.setState(key, value);
  718. # if DISTRHO_PLUGIN_HAS_UI
  719. if (connectedToUI)
  720. sendStateChangeToUI(key, value);
  721. # endif
  722. }
  723. #endif
  724. }
  725. else if (queryingType == 'p')
  726. {
  727. d_stdout("found parameter '%s' '%s'", key.buffer(), value.buffer());
  728. // find parameter with this symbol, and set its value
  729. for (uint32_t j=0; j < paramCount; ++j)
  730. {
  731. if (fPlugin.isParameterOutputOrTrigger(j))
  732. continue;
  733. if (fPlugin.getParameterSymbol(j) != key)
  734. continue;
  735. const float fvalue = fParameterValues[i] = std::atof(value.buffer());
  736. fPlugin.setParameterValue(j, fvalue);
  737. #if DISTRHO_PLUGIN_HAS_UI
  738. if (connectedToUI)
  739. {
  740. // UI parameter updates are handled outside the read loop (after host param restart)
  741. fChangedParameterValues[j + fParameterOffset] = true;
  742. }
  743. #endif
  744. break;
  745. }
  746. }
  747. key.clear();
  748. value.clear();
  749. }
  750. }
  751. }
  752. if (paramCount != 0)
  753. {
  754. if (fComponentHandler != nullptr)
  755. v3_cpp_obj(fComponentHandler)->restart_component(fComponentHandler, V3_RESTART_PARAM_VALUES_CHANGED);
  756. #if DISTRHO_PLUGIN_HAS_UI
  757. if (connectedToUI)
  758. {
  759. for (uint32_t i=0; i < paramCount; ++i)
  760. {
  761. if (fPlugin.isParameterOutputOrTrigger(i))
  762. continue;
  763. fChangedParameterValues[i + fParameterOffset] = false;
  764. sendParameterChangeToUI(i + fParameterOffset, fParameterValues[i]);
  765. }
  766. }
  767. #endif
  768. }
  769. return V3_OK;
  770. }
  771. v3_result getState(v3_bstream** const stream)
  772. {
  773. const uint32_t paramCount = fPlugin.getParameterCount();
  774. #if DISTRHO_PLUGIN_WANT_STATE
  775. const uint32_t stateCount = fPlugin.getStateCount();
  776. #else
  777. const uint32_t stateCount = 0;
  778. #endif
  779. if (stateCount == 0 && paramCount == 0)
  780. {
  781. char buffer = '\0';
  782. int32_t ignored;
  783. return v3_cpp_obj(stream)->write(stream, &buffer, 1, &ignored);
  784. }
  785. #if DISTRHO_PLUGIN_WANT_FULL_STATE
  786. // Update current state
  787. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  788. {
  789. const String& key = cit->first;
  790. fStateMap[key] = fPlugin.getState(key);
  791. }
  792. #endif
  793. String state;
  794. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  795. {
  796. String tmpStr("__dpf_program__\xff");
  797. tmpStr += String(fCurrentProgram);
  798. tmpStr += "\xff";
  799. state += tmpStr;
  800. }
  801. #endif
  802. #if DISTRHO_PLUGIN_WANT_STATE
  803. if (stateCount != 0)
  804. {
  805. state += "__dpf_state_begin__\xff";
  806. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  807. {
  808. const String& key = cit->first;
  809. const String& value = cit->second;
  810. // join key and value
  811. String tmpStr;
  812. tmpStr = key;
  813. tmpStr += "\xff";
  814. tmpStr += value;
  815. tmpStr += "\xff";
  816. state += tmpStr;
  817. }
  818. state += "__dpf_state_end__\xff";
  819. }
  820. #endif
  821. if (paramCount != 0)
  822. {
  823. state += "__dpf_parameters_begin__\xff";
  824. for (uint32_t i=0; i<paramCount; ++i)
  825. {
  826. if (fPlugin.isParameterOutputOrTrigger(i))
  827. continue;
  828. // join key and value
  829. String tmpStr;
  830. tmpStr = fPlugin.getParameterSymbol(i);
  831. tmpStr += "\xff";
  832. tmpStr += String(fPlugin.getParameterValue(i));
  833. tmpStr += "\xff";
  834. state += tmpStr;
  835. }
  836. state += "__dpf_parameters_end__\xff";
  837. }
  838. // terminator
  839. state += "\xfe";
  840. state.replace('\xff', '\0');
  841. // now saving state, carefully until host written bytes matches full state size
  842. const char* buffer = state.buffer();
  843. const int32_t size = static_cast<int32_t>(state.length())+1;
  844. v3_result res;
  845. for (int32_t wrtntotal = 0, wrtn; wrtntotal < size; wrtntotal += wrtn)
  846. {
  847. wrtn = 0;
  848. res = v3_cpp_obj(stream)->write(stream, const_cast<char*>(buffer), size - wrtntotal, &wrtn);
  849. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  850. DISTRHO_SAFE_ASSERT_INT_RETURN(wrtn > 0, wrtn, V3_INTERNAL_ERR);
  851. }
  852. return V3_OK;
  853. }
  854. // ----------------------------------------------------------------------------------------------------------------
  855. // v3_audio_processor interface calls
  856. v3_result setBusArrangements(v3_speaker_arrangement*, int32_t, v3_speaker_arrangement*, int32_t)
  857. {
  858. // TODO
  859. return V3_NOT_IMPLEMENTED;
  860. }
  861. v3_result getBusArrangement(int32_t, int32_t, v3_speaker_arrangement*)
  862. {
  863. // TODO
  864. return V3_NOT_IMPLEMENTED;
  865. }
  866. uint32_t getLatencySamples() const noexcept
  867. {
  868. #if DISTRHO_PLUGIN_WANT_LATENCY
  869. return fPlugin.getLatency();
  870. #else
  871. return 0;
  872. #endif
  873. }
  874. v3_result setupProcessing(v3_process_setup* const setup)
  875. {
  876. DISTRHO_SAFE_ASSERT_RETURN(setup->symbolic_sample_size == V3_SAMPLE_32, V3_INVALID_ARG);
  877. const bool active = fPlugin.isActive();
  878. fPlugin.deactivateIfNeeded();
  879. // TODO process_mode can be V3_REALTIME, V3_PREFETCH, V3_OFFLINE
  880. #if DISTRHO_PLUGIN_HAS_UI
  881. if (d_isNotEqual(setup->sample_rate, fPlugin.getSampleRate()))
  882. fNextSampleRate = setup->sample_rate;
  883. #endif
  884. fPlugin.setSampleRate(setup->sample_rate, true);
  885. fPlugin.setBufferSize(setup->max_block_size, true);
  886. if (active)
  887. fPlugin.activate();
  888. // TODO create dummy buffer of max_block_size length, to use for disabled buses
  889. return V3_OK;
  890. }
  891. v3_result setProcessing(const bool processing)
  892. {
  893. if (processing)
  894. {
  895. if (! fPlugin.isActive())
  896. fPlugin.activate();
  897. }
  898. else
  899. {
  900. fPlugin.deactivate();
  901. }
  902. return V3_OK;
  903. }
  904. v3_result process(v3_process_data* const data)
  905. {
  906. DISTRHO_SAFE_ASSERT_RETURN(data->symbolic_sample_size == V3_SAMPLE_32, V3_INVALID_ARG);
  907. if (! fPlugin.isActive())
  908. {
  909. // host has not activated the plugin yet, nasty!
  910. fPlugin.activate();
  911. }
  912. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  913. if (v3_process_context* const ctx = data->ctx)
  914. {
  915. fTimePosition.playing = ctx->state & V3_PROCESS_CTX_PLAYING;
  916. fTimePosition.bbt.valid = ctx->state & (V3_PROCESS_CTX_TEMPO_VALID|V3_PROCESS_CTX_TIME_SIG_VALID);
  917. // ticksPerBeat is not possible with VST2
  918. fTimePosition.bbt.ticksPerBeat = 1920.0;
  919. if (ctx->state & V3_PROCESS_CTX_CONT_TIME_VALID)
  920. fTimePosition.frame = ctx->continuous_time_in_samples;
  921. else
  922. fTimePosition.frame = ctx->project_time_in_samples;
  923. if (ctx->state & V3_PROCESS_CTX_TEMPO_VALID)
  924. fTimePosition.bbt.beatsPerMinute = ctx->bpm;
  925. else
  926. fTimePosition.bbt.beatsPerMinute = 120.0;
  927. if (ctx->state & (V3_PROCESS_CTX_PROJECT_TIME_VALID|V3_PROCESS_CTX_TIME_SIG_VALID))
  928. {
  929. const double ppqPos = std::abs(ctx->project_time_quarters);
  930. const int ppqPerBar = ctx->time_sig_numerator * 4 / ctx->time_sig_denom;
  931. const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * ctx->time_sig_numerator;
  932. const double rest = std::fmod(barBeats, 1.0);
  933. fTimePosition.bbt.bar = static_cast<int32_t>(ppqPos) / ppqPerBar + 1;
  934. fTimePosition.bbt.beat = static_cast<int32_t>(barBeats - rest + 0.5) + 1;
  935. fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
  936. fTimePosition.bbt.beatsPerBar = ctx->time_sig_numerator;
  937. fTimePosition.bbt.beatType = ctx->time_sig_denom;
  938. if (ctx->project_time_quarters < 0.0)
  939. {
  940. --fTimePosition.bbt.bar;
  941. fTimePosition.bbt.beat = ctx->time_sig_numerator - fTimePosition.bbt.beat + 1;
  942. fTimePosition.bbt.tick = fTimePosition.bbt.ticksPerBeat - fTimePosition.bbt.tick - 1;
  943. }
  944. }
  945. else
  946. {
  947. fTimePosition.bbt.bar = 1;
  948. fTimePosition.bbt.beat = 1;
  949. fTimePosition.bbt.tick = 0.0;
  950. fTimePosition.bbt.beatsPerBar = 4.0f;
  951. fTimePosition.bbt.beatType = 4.0f;
  952. }
  953. fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*
  954. fTimePosition.bbt.beatsPerBar*
  955. (fTimePosition.bbt.bar-1);
  956. fPlugin.setTimePosition(fTimePosition);
  957. }
  958. #endif
  959. if (data->nframes <= 0)
  960. {
  961. updateParameterOutputsAndTriggers();
  962. return V3_OK;
  963. }
  964. const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS != 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1];
  965. /* */ float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS != 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1];
  966. {
  967. int32_t i = 0;
  968. if (data->inputs != nullptr)
  969. {
  970. for (; i < data->inputs->num_channels; ++i)
  971. {
  972. DISTRHO_SAFE_ASSERT_INT_BREAK(i < DISTRHO_PLUGIN_NUM_INPUTS, i);
  973. inputs[i] = data->inputs->channel_buffers_32[i];
  974. }
  975. }
  976. for (; i < std::max(1, DISTRHO_PLUGIN_NUM_INPUTS); ++i)
  977. inputs[i] = nullptr; // TODO use dummy buffer
  978. }
  979. {
  980. int32_t i = 0;
  981. if (data->outputs != nullptr)
  982. {
  983. for (; i < data->outputs->num_channels; ++i)
  984. {
  985. DISTRHO_SAFE_ASSERT_INT_BREAK(i < DISTRHO_PLUGIN_NUM_OUTPUTS, i);
  986. outputs[i] = data->outputs->channel_buffers_32[i];
  987. }
  988. }
  989. for (; i < std::max(1, DISTRHO_PLUGIN_NUM_OUTPUTS); ++i)
  990. outputs[i] = nullptr; // TODO use dummy buffer
  991. }
  992. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  993. fHostEventOutputHandle = data->output_events;
  994. #endif
  995. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  996. uint32_t midiEventCount = 0;
  997. # if DISTRHO_PLUGIN_HAS_UI
  998. while (fNotesRingBuffer.isDataAvailableForReading())
  999. {
  1000. uint8_t midiData[3];
  1001. if (! fNotesRingBuffer.readCustomData(midiData, 3))
  1002. break;
  1003. MidiEvent& midiEvent(fMidiEvents[midiEventCount++]);
  1004. midiEvent.frame = 0;
  1005. midiEvent.size = 3;
  1006. std::memcpy(midiEvent.data, midiData, 3);
  1007. if (midiEventCount == kMaxMidiEvents)
  1008. break;
  1009. }
  1010. # endif
  1011. if (v3_event_list** const eventptr = data->input_events)
  1012. {
  1013. v3_event event;
  1014. for (uint32_t i = 0, count = v3_cpp_obj(eventptr)->get_event_count(eventptr); i < count; ++i)
  1015. {
  1016. if (v3_cpp_obj(eventptr)->get_event(eventptr, i, &event) != V3_OK)
  1017. break;
  1018. // check if event can be encoded as MIDI
  1019. switch (event.type)
  1020. {
  1021. case V3_EVENT_NOTE_ON:
  1022. case V3_EVENT_NOTE_OFF:
  1023. // case V3_EVENT_DATA:
  1024. case V3_EVENT_POLY_PRESSURE:
  1025. // case V3_EVENT_NOTE_EXP_VALUE:
  1026. // case V3_EVENT_NOTE_EXP_TEXT:
  1027. // case V3_EVENT_CHORD:
  1028. // case V3_EVENT_SCALE:
  1029. case V3_EVENT_LEGACY_MIDI_CC_OUT:
  1030. break;
  1031. default:
  1032. continue;
  1033. }
  1034. MidiEvent& midiEvent(fMidiEvents[midiEventCount++]);
  1035. midiEvent.frame = event.sample_offset;
  1036. // encode event as MIDI
  1037. switch (event.type)
  1038. {
  1039. case V3_EVENT_NOTE_ON:
  1040. midiEvent.size = 3;
  1041. midiEvent.data[0] = 0x90 | (event.note_on.channel & 0xf);
  1042. midiEvent.data[1] = event.note_on.pitch;
  1043. midiEvent.data[2] = std::max(0, std::min(127, (int)(event.note_on.velocity * 127)));
  1044. midiEvent.data[3] = 0;
  1045. break;
  1046. case V3_EVENT_NOTE_OFF:
  1047. midiEvent.size = 3;
  1048. midiEvent.data[0] = 0x80 | (event.note_off.channel & 0xf);
  1049. midiEvent.data[1] = event.note_off.pitch;
  1050. midiEvent.data[2] = std::max(0, std::min(127, (int)(event.note_off.velocity * 127)));
  1051. midiEvent.data[3] = 0;
  1052. break;
  1053. case V3_EVENT_POLY_PRESSURE:
  1054. midiEvent.size = 3;
  1055. midiEvent.data[0] = 0xA0 | (event.poly_pressure.channel & 0xf);
  1056. midiEvent.data[1] = event.poly_pressure.pitch;
  1057. midiEvent.data[2] = std::max(0, std::min(127, (int)(event.poly_pressure.pressure * 127)));
  1058. midiEvent.data[3] = 0;
  1059. break;
  1060. case V3_EVENT_LEGACY_MIDI_CC_OUT:
  1061. midiEvent.size = 3;
  1062. midiEvent.data[0] = 0xB0 | (event.midi_cc_out.channel & 0xf);
  1063. midiEvent.data[1] = event.midi_cc_out.cc_number;
  1064. midiEvent.data[2] = event.midi_cc_out.value;
  1065. midiEvent.data[3] = 0;
  1066. // midiEvent.data[3] = event.midi_cc_out.value2; // TODO check when size should be 4
  1067. break;
  1068. default:
  1069. midiEvent.size = 0;
  1070. break;
  1071. }
  1072. if (midiEventCount == kMaxMidiEvents)
  1073. break;
  1074. }
  1075. }
  1076. fPlugin.run(inputs, outputs, data->nframes, fMidiEvents, midiEventCount);
  1077. #else
  1078. fPlugin.run(inputs, outputs, data->nframes);
  1079. #endif
  1080. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1081. fHostEventOutputHandle = nullptr;
  1082. #endif
  1083. updateParameterOutputsAndTriggers();
  1084. return V3_OK;
  1085. }
  1086. uint32_t getTailSamples() const noexcept
  1087. {
  1088. return 0;
  1089. }
  1090. // ----------------------------------------------------------------------------------------------------------------
  1091. // v3_edit_controller interface calls
  1092. #if 0
  1093. v3_result setComponentState(v3_bstream*, void*)
  1094. {
  1095. // TODO
  1096. return V3_NOT_IMPLEMENTED;
  1097. }
  1098. v3_result setState(v3_bstream*, void*)
  1099. {
  1100. // TODO
  1101. return V3_NOT_IMPLEMENTED;
  1102. }
  1103. v3_result getState(v3_bstream*, void*)
  1104. {
  1105. // TODO
  1106. return V3_NOT_IMPLEMENTED;
  1107. }
  1108. #endif
  1109. int32_t getParameterCount() const noexcept
  1110. {
  1111. return fRealParameterCount;
  1112. }
  1113. v3_result getParameterInfo(int32_t rindex, v3_param_info* const info) const noexcept
  1114. {
  1115. DISTRHO_SAFE_ASSERT_RETURN(rindex >= 0, V3_INVALID_ARG);
  1116. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1117. if (rindex == 0)
  1118. {
  1119. std::memset(info, 0, sizeof(v3_param_info));
  1120. info->param_id = rindex;
  1121. info->flags = V3_PARAM_CAN_AUTOMATE | V3_PARAM_IS_LIST | V3_PARAM_PROGRAM_CHANGE;
  1122. info->step_count = fProgramCountMinusOne;
  1123. strncpy_utf16(info->title, "Current Program", 128);
  1124. strncpy_utf16(info->short_title, "Program", 128);
  1125. return V3_OK;
  1126. }
  1127. --rindex;
  1128. #endif
  1129. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1130. if (rindex <= 130*16)
  1131. {
  1132. std::memset(info, 0, sizeof(v3_param_info));
  1133. info->param_id = rindex;
  1134. info->flags = V3_PARAM_CAN_AUTOMATE | V3_PARAM_IS_HIDDEN;
  1135. info->step_count = 127;
  1136. char ccstr[24];
  1137. snprintf(ccstr, sizeof(ccstr)-1, "MIDI Ch. %d CC %d", rindex / 130 + 1, rindex % 130);
  1138. strncpy_utf16(info->title, ccstr, 128);
  1139. snprintf(ccstr, sizeof(ccstr)-1, "Ch.%d CC%d", rindex / 130 + 1, rindex % 130);
  1140. strncpy_utf16(info->short_title, ccstr+5, 128);
  1141. return V3_OK;
  1142. }
  1143. rindex -= 130*16;
  1144. #endif
  1145. const uint32_t index = static_cast<uint32_t>(rindex);
  1146. DISTRHO_SAFE_ASSERT_UINT_RETURN(index < fPlugin.getParameterCount(), index, V3_INVALID_ARG);
  1147. // set up flags
  1148. int32_t flags = 0;
  1149. const auto desig = fPlugin.getParameterDesignation(index);
  1150. const auto hints = fPlugin.getParameterHints(index);
  1151. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  1152. switch (desig)
  1153. {
  1154. case kParameterDesignationNull:
  1155. break;
  1156. case kParameterDesignationBypass:
  1157. flags |= V3_PARAM_IS_BYPASS;
  1158. break;
  1159. }
  1160. if (hints & kParameterIsAutomable)
  1161. flags |= V3_PARAM_CAN_AUTOMATE;
  1162. if (hints & kParameterIsOutput)
  1163. flags |= V3_PARAM_READ_ONLY;
  1164. // TODO V3_PARAM_IS_LIST
  1165. // set up step_count
  1166. int32_t step_count = 0;
  1167. if (hints & kParameterIsBoolean)
  1168. step_count = 1;
  1169. if ((hints & kParameterIsInteger) && ranges.max - ranges.min > 1)
  1170. step_count = ranges.max - ranges.min - 1;
  1171. std::memset(info, 0, sizeof(v3_param_info));
  1172. info->param_id = index + fParameterOffset;
  1173. info->flags = flags;
  1174. info->step_count = step_count;
  1175. info->default_normalised_value = ranges.getNormalizedValue(ranges.def);
  1176. // int32_t unit_id;
  1177. strncpy_utf16(info->title, fPlugin.getParameterName(index), 128);
  1178. strncpy_utf16(info->short_title, fPlugin.getParameterShortName(index), 128);
  1179. strncpy_utf16(info->units, fPlugin.getParameterUnit(index), 128);
  1180. return V3_OK;
  1181. }
  1182. v3_result getParameterStringForValue(v3_param_id rindex, const double normalised, v3_str_128 output)
  1183. {
  1184. DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, V3_INVALID_ARG);
  1185. DISTRHO_SAFE_ASSERT_RETURN(normalised >= 0.0 && normalised <= 1.0, V3_INVALID_ARG);
  1186. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1187. if (rindex == 0)
  1188. {
  1189. const uint32_t program = std::round(normalised * fProgramCountMinusOne);
  1190. strncpy_utf16(output, fPlugin.getProgramName(program), 128);
  1191. return V3_OK;
  1192. }
  1193. --rindex;
  1194. #endif
  1195. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1196. if (rindex <= 130*16)
  1197. {
  1198. snprintf_f32_utf16(output, std::round(normalised * 127), 128);
  1199. return V3_OK;
  1200. }
  1201. rindex -= 130*16;
  1202. #endif
  1203. const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex));
  1204. snprintf_f32_utf16(output, ranges.getUnnormalizedValue(normalised), 128);
  1205. return V3_OK;
  1206. }
  1207. v3_result getParameterValueForString(v3_param_id rindex, int16_t*, double*)
  1208. {
  1209. DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, V3_INVALID_ARG);
  1210. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1211. if (rindex == 0)
  1212. {
  1213. // TODO find program index based on name
  1214. return V3_NOT_IMPLEMENTED;
  1215. }
  1216. --rindex;
  1217. #endif
  1218. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1219. if (rindex <= 130*16)
  1220. {
  1221. // TODO
  1222. return V3_NOT_IMPLEMENTED;
  1223. }
  1224. rindex -= 130*16;
  1225. #endif
  1226. // TODO
  1227. return V3_NOT_IMPLEMENTED;
  1228. }
  1229. double normalisedParameterToPlain(v3_param_id rindex, const double normalised)
  1230. {
  1231. DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, 0.0);
  1232. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1233. if (rindex == 0)
  1234. return std::round(normalised * fProgramCountMinusOne);
  1235. --rindex;
  1236. #endif
  1237. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1238. if (rindex <= 130*16)
  1239. return std::round(normalised * 127);
  1240. rindex -= 130*16;
  1241. #endif
  1242. const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex));
  1243. return ranges.getUnnormalizedValue(normalised);
  1244. }
  1245. double plainParameterToNormalised(v3_param_id rindex, const double plain)
  1246. {
  1247. DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, 0.0);
  1248. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1249. if (rindex == 0)
  1250. return std::max(0.0, std::min(1.0, plain / fProgramCountMinusOne));
  1251. --rindex;
  1252. #endif
  1253. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1254. if (rindex <= 130*16)
  1255. return std::max(0.0, std::min(1.0, plain / 127));
  1256. rindex -= 130*16;
  1257. #endif
  1258. const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex));
  1259. return ranges.getNormalizedValue(plain);
  1260. }
  1261. double getParameterNormalized(v3_param_id rindex)
  1262. {
  1263. DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, 0.0);
  1264. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1265. if (rindex == 0)
  1266. return std::max(0.0, std::min(1.0, (double)fCurrentProgram / fProgramCountMinusOne));
  1267. --rindex;
  1268. #endif
  1269. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1270. if (rindex <= 130*16)
  1271. {
  1272. // TODO
  1273. return 0.0;
  1274. }
  1275. rindex -= 130*16;
  1276. #endif
  1277. const float value = fPlugin.getParameterValue(rindex);
  1278. const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex));
  1279. return ranges.getNormalizedValue(value);
  1280. }
  1281. v3_result setParameterNormalized(v3_param_id rindex, const double value)
  1282. {
  1283. DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, V3_INVALID_ARG);
  1284. DISTRHO_SAFE_ASSERT_RETURN(value >= 0.0 && value <= 1.0, V3_INVALID_ARG);
  1285. #if DISTRHO_PLUGIN_HAS_UI
  1286. const uint32_t orindex = rindex;
  1287. #endif
  1288. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1289. if (rindex == 0)
  1290. {
  1291. fCurrentProgram = std::round(value * fProgramCountMinusOne);
  1292. fPlugin.loadProgram(fCurrentProgram);
  1293. for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
  1294. {
  1295. if (fPlugin.isParameterOutputOrTrigger(i))
  1296. continue;
  1297. fParameterValues[i] = fPlugin.getParameterValue(i);
  1298. }
  1299. if (fComponentHandler != nullptr)
  1300. v3_cpp_obj(fComponentHandler)->restart_component(fComponentHandler, V3_RESTART_PARAM_VALUES_CHANGED);
  1301. # if DISTRHO_PLUGIN_HAS_UI
  1302. fChangedParameterValues[rindex] = true;
  1303. # endif
  1304. return V3_OK;
  1305. }
  1306. --rindex;
  1307. #endif
  1308. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1309. if (rindex <= 130*16)
  1310. {
  1311. // TODO
  1312. fChangedParameterValues[rindex] = true;
  1313. return V3_NOT_IMPLEMENTED;
  1314. }
  1315. rindex -= 130*16;
  1316. #endif
  1317. const uint32_t hints = fPlugin.getParameterHints(rindex);
  1318. const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex));
  1319. float realValue = ranges.getUnnormalizedValue(value);
  1320. if (hints & kParameterIsBoolean)
  1321. {
  1322. const float midRange = ranges.min + (ranges.max - ranges.min) / 2.0f;
  1323. realValue = realValue > midRange ? ranges.max : ranges.min;
  1324. }
  1325. if (hints & kParameterIsInteger)
  1326. {
  1327. realValue = std::round(realValue);
  1328. }
  1329. fParameterValues[rindex] = realValue;
  1330. fPlugin.setParameterValue(rindex, realValue);
  1331. #if DISTRHO_PLUGIN_HAS_UI
  1332. fChangedParameterValues[orindex] = true;
  1333. #endif
  1334. return V3_OK;
  1335. }
  1336. v3_result setComponentHandler(v3_component_handler** const handler) noexcept
  1337. {
  1338. fComponentHandler = handler;
  1339. return V3_OK;
  1340. }
  1341. #if DISTRHO_PLUGIN_HAS_UI
  1342. // ----------------------------------------------------------------------------------------------------------------
  1343. // v3_connection_point interface calls
  1344. void connect(v3_connection_point** const other)
  1345. {
  1346. DISTRHO_SAFE_ASSERT(fConnectedToUI == false);
  1347. fConnection = other;
  1348. fConnectedToUI = false;
  1349. }
  1350. void disconnect()
  1351. {
  1352. fConnection = nullptr;
  1353. fConnectedToUI = false;
  1354. }
  1355. v3_result notify(v3_message** const message)
  1356. {
  1357. const char* const msgid = v3_cpp_obj(message)->get_message_id(message);
  1358. DISTRHO_SAFE_ASSERT_RETURN(msgid != nullptr, V3_INVALID_ARG);
  1359. v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message);
  1360. DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr, V3_INVALID_ARG);
  1361. # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1362. if (std::strcmp(msgid, "midi") == 0)
  1363. {
  1364. uint8_t* data;
  1365. uint32_t size;
  1366. v3_result res;
  1367. res = v3_cpp_obj(attrs)->get_binary(attrs, "data", (const void**)&data, &size);
  1368. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1369. // known maximum size
  1370. DISTRHO_SAFE_ASSERT_UINT_RETURN(size == 3, size, V3_INTERNAL_ERR);
  1371. return fNotesRingBuffer.writeCustomData(data, size) && fNotesRingBuffer.commitWrite() ? V3_OK : V3_NOMEM;
  1372. }
  1373. # endif
  1374. if (std::strcmp(msgid, "init") == 0)
  1375. {
  1376. DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr, V3_INTERNAL_ERR);
  1377. fConnectedToUI = true;
  1378. if (const double sampleRate = fNextSampleRate)
  1379. {
  1380. fNextSampleRate = 0.0;
  1381. sendSampleRateToUI(sampleRate);
  1382. }
  1383. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  1384. fChangedParameterValues[0] = false;
  1385. sendParameterChangeToUI(0, fCurrentProgram);
  1386. # endif
  1387. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  1388. // Update current state from plugin side
  1389. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  1390. {
  1391. const String& key = cit->first;
  1392. fStateMap[key] = fPlugin.getState(key);
  1393. }
  1394. # endif
  1395. # if DISTRHO_PLUGIN_WANT_STATE
  1396. // Set state
  1397. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  1398. {
  1399. const String& key = cit->first;
  1400. const String& value = cit->second;
  1401. sendStateChangeToUI(key, value);
  1402. }
  1403. # endif
  1404. for (uint32_t i=fParameterOffset; i<fRealParameterCount; ++i)
  1405. {
  1406. fChangedParameterValues[i] = false;
  1407. sendParameterChangeToUI(i, fPlugin.getParameterValue(i - fParameterOffset));
  1408. }
  1409. sendReadyToUI();
  1410. return V3_OK;
  1411. }
  1412. if (std::strcmp(msgid, "idle") == 0)
  1413. {
  1414. DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr, V3_INTERNAL_ERR);
  1415. DISTRHO_SAFE_ASSERT_RETURN(fConnectedToUI, V3_INTERNAL_ERR);
  1416. for (uint32_t i=0, rindex; i<fRealParameterCount; ++i)
  1417. {
  1418. if (! fChangedParameterValues[i])
  1419. continue;
  1420. fChangedParameterValues[i] = false;
  1421. rindex = i;
  1422. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  1423. if (rindex == 0)
  1424. {
  1425. sendParameterChangeToUI(rindex, fCurrentProgram);
  1426. continue;
  1427. }
  1428. --rindex;
  1429. # endif
  1430. # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1431. if (rindex <= 130*16)
  1432. continue;
  1433. rindex -= 130*16;
  1434. # endif
  1435. sendParameterChangeToUI(rindex + fParameterOffset, fParameterValues[rindex]);
  1436. }
  1437. sendReadyToUI();
  1438. return V3_OK;
  1439. }
  1440. if (std::strcmp(msgid, "close") == 0)
  1441. {
  1442. fConnectedToUI = false;
  1443. DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr, V3_INTERNAL_ERR);
  1444. return V3_OK;
  1445. }
  1446. if (std::strcmp(msgid, "parameter-edit") == 0)
  1447. {
  1448. DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, V3_INTERNAL_ERR);
  1449. int64_t rindex;
  1450. int64_t started;
  1451. v3_result res;
  1452. res = v3_cpp_obj(attrs)->get_int(attrs, "rindex", &rindex);
  1453. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1454. res = v3_cpp_obj(attrs)->get_int(attrs, "started", &started);
  1455. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1456. rindex -= fParameterOffset;
  1457. DISTRHO_SAFE_ASSERT_RETURN(rindex >= 0, V3_INTERNAL_ERR);
  1458. return started != 0 ? v3_cpp_obj(fComponentHandler)->begin_edit(fComponentHandler, rindex)
  1459. : v3_cpp_obj(fComponentHandler)->end_edit(fComponentHandler, rindex);
  1460. }
  1461. if (std::strcmp(msgid, "parameter-set") == 0)
  1462. {
  1463. int64_t rindex;
  1464. double value;
  1465. v3_result res;
  1466. res = v3_cpp_obj(attrs)->get_int(attrs, "rindex", &rindex);
  1467. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1468. DISTRHO_SAFE_ASSERT_INT_RETURN(rindex >= fParameterOffset, rindex, V3_INTERNAL_ERR);
  1469. res = v3_cpp_obj(attrs)->get_float(attrs, "value", &value);
  1470. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1471. const uint32_t index = static_cast<uint32_t>(rindex - fParameterOffset);
  1472. return requestParameterValueChange(index, value) ? V3_OK : V3_INTERNAL_ERR;
  1473. }
  1474. # if DISTRHO_PLUGIN_WANT_STATE
  1475. if (std::strcmp(msgid, "state-set") == 0)
  1476. {
  1477. int16_t* key16;
  1478. int16_t* value16;
  1479. uint32_t keySize, valueSize;
  1480. v3_result res;
  1481. res = v3_cpp_obj(attrs)->get_binary(attrs, "key", (const void**)&key16, &keySize);
  1482. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1483. res = v3_cpp_obj(attrs)->get_binary(attrs, "value", (const void**)&value16, &valueSize);
  1484. DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res);
  1485. // do cheap inline conversion
  1486. char* const key = (char*)key16;
  1487. char* const value = (char*)value16;
  1488. for (uint32_t i=0; i<keySize/sizeof(int16_t); ++i)
  1489. key[i] = key16[i];
  1490. for (uint32_t i=0; i<valueSize/sizeof(int16_t); ++i)
  1491. value[i] = value16[i];
  1492. fPlugin.setState(key, value);
  1493. // save this key as needed
  1494. if (fPlugin.wantStateKey(key))
  1495. {
  1496. for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
  1497. {
  1498. const String& dkey(it->first);
  1499. if (dkey == key)
  1500. {
  1501. it->second = value;
  1502. return V3_OK;
  1503. }
  1504. }
  1505. d_stderr("Failed to find plugin state with key \"%s\"", key);
  1506. }
  1507. return V3_OK;
  1508. }
  1509. # endif
  1510. return V3_NOT_IMPLEMENTED;
  1511. }
  1512. #endif
  1513. // ----------------------------------------------------------------------------------------------------------------
  1514. private:
  1515. // Plugin
  1516. PluginExporter fPlugin;
  1517. // VST3 stuff
  1518. v3_component_handler** fComponentHandler;
  1519. #if DISTRHO_PLUGIN_HAS_UI
  1520. v3_connection_point** fConnection;
  1521. #endif
  1522. // Temporary data
  1523. const uint32_t fParameterOffset;
  1524. const uint32_t fRealParameterCount; // regular parameters + current program
  1525. float* fParameterValues;
  1526. bool* fChangedParameterValues;
  1527. #if DISTRHO_PLUGIN_HAS_UI
  1528. bool fConnectedToUI;
  1529. double fNextSampleRate; // if not zero, report to UI
  1530. #endif
  1531. #if DISTRHO_PLUGIN_WANT_LATENCY
  1532. uint32_t fLastKnownLatency;
  1533. #endif
  1534. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1535. MidiEvent fMidiEvents[kMaxMidiEvents];
  1536. # if DISTRHO_PLUGIN_HAS_UI
  1537. SmallStackRingBuffer fNotesRingBuffer;
  1538. # endif
  1539. #endif
  1540. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1541. v3_event_list** fHostEventOutputHandle;
  1542. #endif
  1543. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1544. uint32_t fCurrentProgram;
  1545. const uint32_t fProgramCountMinusOne;
  1546. #endif
  1547. #if DISTRHO_PLUGIN_WANT_STATE
  1548. StringMap fStateMap;
  1549. #endif
  1550. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  1551. TimePosition fTimePosition;
  1552. #endif
  1553. // ----------------------------------------------------------------------------------------------------------------
  1554. // helper functions called during process, cannot block
  1555. void updateParameterOutputsAndTriggers()
  1556. {
  1557. float curValue;
  1558. for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i)
  1559. {
  1560. if (fPlugin.isParameterOutput(i))
  1561. {
  1562. // NOTE: no output parameter support in VST3, simulate it here
  1563. curValue = fPlugin.getParameterValue(i);
  1564. if (d_isEqual(curValue, fParameterValues[i]))
  1565. continue;
  1566. fParameterValues[i] = curValue;
  1567. #if DISTRHO_PLUGIN_HAS_UI
  1568. fChangedParameterValues[i] = true;
  1569. #endif
  1570. }
  1571. else if (fPlugin.isParameterTrigger(i))
  1572. {
  1573. // NOTE: no trigger support in VST3 parameters, simulate it here
  1574. curValue = fPlugin.getParameterValue(i);
  1575. if (d_isEqual(curValue, fPlugin.getParameterDefault(i)))
  1576. continue;
  1577. fPlugin.setParameterValue(i, curValue);
  1578. #if DISTRHO_PLUGIN_HAS_UI
  1579. fChangedParameterValues[i] = true;
  1580. #endif
  1581. }
  1582. else
  1583. {
  1584. continue;
  1585. }
  1586. requestParameterValueChange(i, curValue);
  1587. }
  1588. #if DISTRHO_PLUGIN_WANT_LATENCY
  1589. const uint32_t latency = fPlugin.getLatency();
  1590. if (fLastKnownLatency != latency)
  1591. {
  1592. fLastKnownLatency = latency;
  1593. if (fComponentHandler != nullptr)
  1594. v3_cpp_obj(fComponentHandler)->restart_component(fComponentHandler, V3_RESTART_LATENCY_CHANGED);
  1595. }
  1596. #endif
  1597. }
  1598. #if DISTRHO_PLUGIN_HAS_UI
  1599. // ----------------------------------------------------------------------------------------------------------------
  1600. // helper functions called during message passing, can block
  1601. void sendSampleRateToUI(const double sampleRate)
  1602. {
  1603. v3_message** const message = dpf_message_create("sample-rate");
  1604. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
  1605. v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message);
  1606. DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,);
  1607. v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 2);
  1608. v3_cpp_obj(attrlist)->set_float(attrlist, "value", sampleRate);
  1609. v3_cpp_obj(fConnection)->notify(fConnection, message);
  1610. v3_cpp_obj_unref(message);
  1611. }
  1612. void sendParameterChangeToUI(const v3_param_id rindex, const double value)
  1613. {
  1614. v3_message** const message = dpf_message_create("parameter-set");
  1615. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
  1616. v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message);
  1617. DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,);
  1618. v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 2);
  1619. v3_cpp_obj(attrlist)->set_int(attrlist, "rindex", rindex);
  1620. v3_cpp_obj(attrlist)->set_float(attrlist, "value", value);
  1621. v3_cpp_obj(fConnection)->notify(fConnection, message);
  1622. v3_cpp_obj_unref(message);
  1623. }
  1624. void sendStateChangeToUI(const char* const key, const char* const value)
  1625. {
  1626. v3_message** const message = dpf_message_create("state-set");
  1627. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
  1628. v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message);
  1629. DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,);
  1630. v3_attribute_list_utf8** utf8attrlist = nullptr;
  1631. DISTRHO_SAFE_ASSERT_RETURN(v3_cpp_obj_query_interface(attrlist, v3_attribute_list_utf8_iid, &utf8attrlist) == V3_OK,);
  1632. DISTRHO_SAFE_ASSERT_RETURN(utf8attrlist != nullptr,);
  1633. v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 2);
  1634. v3_cpp_obj(utf8attrlist)->set_string_utf8(utf8attrlist, "key", key);
  1635. v3_cpp_obj(utf8attrlist)->set_string_utf8(utf8attrlist, "value", value);
  1636. v3_cpp_obj(fConnection)->notify(fConnection, message);
  1637. v3_cpp_obj_unref(message);
  1638. }
  1639. void sendReadyToUI()
  1640. {
  1641. v3_message** const message = dpf_message_create("ready");
  1642. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
  1643. v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message);
  1644. DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,);
  1645. v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 2);
  1646. v3_cpp_obj(fConnection)->notify(fConnection, message);
  1647. v3_cpp_obj_unref(message);
  1648. }
  1649. #endif
  1650. // ----------------------------------------------------------------------------------------------------------------
  1651. // DPF callbacks
  1652. bool requestParameterValueChange(const uint32_t index, const float value)
  1653. {
  1654. DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false);
  1655. const uint32_t rindex = index + fParameterOffset;
  1656. const double normalized = fPlugin.getParameterRanges(index).getNormalizedValue(value);
  1657. const v3_result res_edit = v3_cpp_obj(fComponentHandler)->begin_edit(fComponentHandler, rindex);
  1658. DISTRHO_SAFE_ASSERT_INT_RETURN(res_edit == V3_TRUE || res_edit == V3_FALSE, res_edit, res_edit);
  1659. const v3_result res_perf = v3_cpp_obj(fComponentHandler)->perform_edit(fComponentHandler, rindex, normalized);
  1660. if (res_perf == V3_TRUE)
  1661. fParameterValues[index] = value;
  1662. if (res_edit == V3_TRUE)
  1663. v3_cpp_obj(fComponentHandler)->end_edit(fComponentHandler, rindex);
  1664. return res_perf == V3_TRUE;
  1665. }
  1666. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  1667. static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
  1668. {
  1669. return ((PluginVst3*)ptr)->requestParameterValueChange(index, value);
  1670. }
  1671. #endif
  1672. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1673. bool writeMidi(const MidiEvent& midiEvent)
  1674. {
  1675. DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fHostEventOutputHandle != nullptr, false);
  1676. v3_event event;
  1677. std::memset(&event, 0, sizeof(event));
  1678. event.sample_offset = midiEvent.frame;
  1679. const uint8_t* const data = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data;
  1680. switch (data[0] & 0xf0)
  1681. {
  1682. case 0x80:
  1683. event.type = V3_EVENT_NOTE_OFF;
  1684. event.note_off.channel = data[0] & 0xf;
  1685. event.note_off.pitch = data[1];
  1686. event.note_off.velocity = (float)data[2] / 127.0f;
  1687. // int32_t note_id;
  1688. // float tuning;
  1689. break;
  1690. case 0x90:
  1691. event.type = V3_EVENT_NOTE_ON;
  1692. event.note_on.channel = data[0] & 0xf;
  1693. event.note_on.pitch = data[1];
  1694. // float tuning;
  1695. event.note_on.velocity = (float)data[2] / 127.0f;
  1696. // int32_t length;
  1697. // int32_t note_id;
  1698. break;
  1699. case 0xA0:
  1700. event.type = V3_EVENT_POLY_PRESSURE;
  1701. event.poly_pressure.channel = data[0] & 0xf;
  1702. event.poly_pressure.pitch = data[1];
  1703. event.poly_pressure.pressure = (float)data[2] / 127.0f;
  1704. // int32_t note_id;
  1705. break;
  1706. case 0xB0:
  1707. event.type = V3_EVENT_LEGACY_MIDI_CC_OUT;
  1708. event.midi_cc_out.channel = data[0] & 0xf;
  1709. event.midi_cc_out.cc_number = data[1];
  1710. event.midi_cc_out.value = data[2];
  1711. event.midi_cc_out.value2 = midiEvent.size == 4 ? data[3] : 0;
  1712. break;
  1713. default:
  1714. return true;
  1715. }
  1716. return v3_cpp_obj(fHostEventOutputHandle)->add_event(fHostEventOutputHandle, &event) == V3_OK;
  1717. }
  1718. static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
  1719. {
  1720. return ((PluginVst3*)ptr)->writeMidi(midiEvent);
  1721. }
  1722. #endif
  1723. };
  1724. // --------------------------------------------------------------------------------------------------------------------
  1725. /**
  1726. * VST3 low-level pointer thingies follow, proceed with care.
  1727. */
  1728. // --------------------------------------------------------------------------------------------------------------------
  1729. struct dpf_attribute_value {
  1730. char type; // one of: i, f, s, b
  1731. union {
  1732. int64_t integer;
  1733. double v_float;
  1734. int16_t* string;
  1735. struct {
  1736. void* ptr;
  1737. uint32_t size;
  1738. } binary;
  1739. };
  1740. };
  1741. static void dpf_attribute_list_free(std::map<std::string, dpf_attribute_value>& attrs)
  1742. {
  1743. for (auto& it : attrs)
  1744. {
  1745. dpf_attribute_value& v(it.second);
  1746. switch (v.type)
  1747. {
  1748. case 's':
  1749. case 'b':
  1750. std::free(v.binary.ptr);
  1751. break;
  1752. }
  1753. }
  1754. }
  1755. // --------------------------------------------------------------------------------------------------------------------
  1756. // dpf_attribute_list_utf8 (the custom variant)
  1757. struct v3_attribute_list_utf8_cpp : v3_funknown {
  1758. v3_attribute_list_utf8 attr;
  1759. };
  1760. struct dpf_attribute_list_utf8 : v3_attribute_list_utf8_cpp {
  1761. std::map<std::string, dpf_attribute_value>& attrs;
  1762. dpf_attribute_list_utf8(std::map<std::string, dpf_attribute_value>& a)
  1763. : attrs(a)
  1764. {
  1765. static const uint8_t* kSupportedInterfaces[] = {
  1766. v3_funknown_iid,
  1767. v3_attribute_list_utf8_iid
  1768. };
  1769. // ------------------------------------------------------------------------------------------------------------
  1770. // v3_funknown
  1771. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1772. {
  1773. d_stdout("dpf_attribute_list_utf8::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1774. *iface = NULL;
  1775. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1776. for (const uint8_t* interface_iid : kSupportedInterfaces)
  1777. {
  1778. if (v3_tuid_match(interface_iid, iid))
  1779. {
  1780. *iface = self;
  1781. return V3_OK;
  1782. }
  1783. }
  1784. return V3_NO_INTERFACE;
  1785. };
  1786. // there is only a single instance of this, so we don't have to care here
  1787. ref = []V3_API(void*) -> uint32_t { return 1; };
  1788. unref = []V3_API(void*) -> uint32_t { return 0; };
  1789. // ------------------------------------------------------------------------------------------------------------
  1790. // v3_attribute_list_utf8
  1791. attr.set_string_utf8 = []V3_API(void* self, const char* id, const char* string) -> v3_result
  1792. {
  1793. dpf_attribute_list_utf8* const attr = *(dpf_attribute_list_utf8**)self;
  1794. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1795. const uint32_t size = std::strlen(string) + 1;
  1796. int16_t* const copy = (int16_t*)std::malloc(sizeof(int16_t) * size);
  1797. DISTRHO_SAFE_ASSERT_RETURN(copy != nullptr, V3_NOMEM);
  1798. DISTRHO_NAMESPACE::strncpy_utf16(copy, string, size);
  1799. dpf_attribute_value& attrval(attr->attrs[id]);
  1800. attrval.type = 's';
  1801. attrval.binary.ptr = copy;
  1802. attrval.binary.size = sizeof(int16_t) * size;
  1803. return V3_OK;
  1804. };
  1805. attr.get_string_utf8 = []V3_API(void* self, const char* id, char*, uint32_t) -> v3_result
  1806. {
  1807. dpf_attribute_list_utf8* const attr = *(dpf_attribute_list_utf8**)self;
  1808. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1809. if (attr->attrs.find(id) == attr->attrs.end())
  1810. return V3_INVALID_ARG;
  1811. return V3_NOT_IMPLEMENTED;
  1812. };
  1813. }
  1814. };
  1815. // --------------------------------------------------------------------------------------------------------------------
  1816. // dpf_attribute_list
  1817. struct dpf_attribute_list : v3_attribute_list_cpp {
  1818. ScopedPointer<dpf_attribute_list_utf8> attrutf8;
  1819. std::map<std::string, dpf_attribute_value> attrs;
  1820. dpf_attribute_list()
  1821. {
  1822. static const uint8_t* kSupportedInterfacesBase[] = {
  1823. v3_funknown_iid,
  1824. v3_attribute_list_iid
  1825. };
  1826. // ------------------------------------------------------------------------------------------------------------
  1827. // v3_funknown
  1828. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1829. {
  1830. // d_stdout("dpf_attribute_list::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1831. *iface = NULL;
  1832. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1833. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  1834. {
  1835. if (v3_tuid_match(interface_iid, iid))
  1836. {
  1837. *iface = self;
  1838. return V3_OK;
  1839. }
  1840. }
  1841. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1842. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NO_INTERFACE);
  1843. if (v3_tuid_match(v3_attribute_list_utf8_iid, iid))
  1844. {
  1845. if (attr->attrutf8 == nullptr)
  1846. attr->attrutf8 = new dpf_attribute_list_utf8(attr->attrs);
  1847. *iface = &attr->attrutf8;
  1848. return V3_OK;
  1849. }
  1850. return V3_NO_INTERFACE;
  1851. };
  1852. // there is only a single instance of this, so we don't have to care here
  1853. ref = []V3_API(void*) -> uint32_t { return 1; };
  1854. unref = []V3_API(void*) -> uint32_t { return 0; };
  1855. // ------------------------------------------------------------------------------------------------------------
  1856. // v3_attribute_list
  1857. attrlist.set_int = []V3_API(void* self, const char* id, int64_t value) -> v3_result
  1858. {
  1859. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1860. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1861. dpf_attribute_value& attrval(attr->attrs[id]);
  1862. attrval.type = 'i';
  1863. attrval.integer = value;
  1864. return V3_OK;
  1865. };
  1866. attrlist.get_int = []V3_API(void* self, const char* id, int64_t* value) -> v3_result
  1867. {
  1868. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1869. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1870. if (attr->attrs.find(id) == attr->attrs.end())
  1871. return V3_INVALID_ARG;
  1872. const dpf_attribute_value& attrval(attr->attrs[id]);
  1873. DISTRHO_SAFE_ASSERT_RETURN(attrval.type == 'i', V3_INVALID_ARG);
  1874. *value = attrval.integer;
  1875. return V3_OK;
  1876. };
  1877. attrlist.set_float = []V3_API(void* self, const char* id, double value) -> v3_result
  1878. {
  1879. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1880. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1881. dpf_attribute_value& attrval(attr->attrs[id]);
  1882. attrval.type = 'f';
  1883. attrval.v_float = value;
  1884. return V3_OK;
  1885. };
  1886. attrlist.get_float = []V3_API(void* self, const char* id, double* value) -> v3_result
  1887. {
  1888. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1889. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1890. if (attr->attrs.find(id) == attr->attrs.end())
  1891. return V3_INVALID_ARG;
  1892. const dpf_attribute_value& attrval(attr->attrs[id]);
  1893. DISTRHO_SAFE_ASSERT_RETURN(attrval.type == 'f', V3_INVALID_ARG);
  1894. *value = attrval.v_float;
  1895. return V3_OK;
  1896. };
  1897. attrlist.set_string = []V3_API(void* self, const char* id, const int16_t* /*string*/) -> v3_result
  1898. {
  1899. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1900. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1901. dpf_attribute_value& attrval(attr->attrs[id]);
  1902. attrval.type = 's';
  1903. attrval.binary.ptr = nullptr;
  1904. attrval.binary.size = 0;
  1905. return V3_NOT_IMPLEMENTED;
  1906. };
  1907. attrlist.get_string = []V3_API(void* self, const char* id, int16_t* /*string*/, uint32_t /*size*/) -> v3_result
  1908. {
  1909. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1910. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1911. if (attr->attrs.find(id) == attr->attrs.end())
  1912. return V3_INVALID_ARG;
  1913. const dpf_attribute_value& attrval(attr->attrs[id]);
  1914. DISTRHO_SAFE_ASSERT_RETURN(attrval.type == 's', V3_INVALID_ARG);
  1915. return V3_NOT_IMPLEMENTED;
  1916. };
  1917. attrlist.set_binary = []V3_API(void* self, const char* id, const void* data, uint32_t size) -> v3_result
  1918. {
  1919. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1920. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1921. void* const copy = std::malloc(size);
  1922. DISTRHO_SAFE_ASSERT_RETURN(copy != nullptr, V3_NOMEM);
  1923. std::memcpy(copy, data, size);
  1924. dpf_attribute_value& attrval(attr->attrs[id]);
  1925. attrval.type = 'b';
  1926. attrval.binary.ptr = copy;
  1927. attrval.binary.size = size;
  1928. return V3_NOT_IMPLEMENTED;
  1929. };
  1930. attrlist.get_binary = []V3_API(void* self, const char* id, const void** data, uint32_t* size) -> v3_result
  1931. {
  1932. dpf_attribute_list* const attr = *(dpf_attribute_list**)self;
  1933. DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED);
  1934. if (attr->attrs.find(id) == attr->attrs.end())
  1935. return V3_INVALID_ARG;
  1936. const dpf_attribute_value& attrval(attr->attrs[id]);
  1937. DISTRHO_SAFE_ASSERT_RETURN(attrval.type == 's' || attrval.type == 'b', V3_INVALID_ARG);
  1938. *data = attrval.binary.ptr;
  1939. *size = attrval.binary.size;
  1940. return V3_OK;
  1941. };
  1942. }
  1943. };
  1944. // --------------------------------------------------------------------------------------------------------------------
  1945. // dpf_message
  1946. struct dpf_message : v3_message_cpp {
  1947. std::atomic<int> refcounter;
  1948. ScopedPointer<dpf_message>* self;
  1949. ScopedPointer<dpf_attribute_list> attrlist;
  1950. String id;
  1951. dpf_message(ScopedPointer<dpf_message>* const s, const char* const id2)
  1952. : self(s),
  1953. id(id2)
  1954. {
  1955. static const uint8_t* kSupportedInterfaces[] = {
  1956. v3_funknown_iid,
  1957. v3_message_iid
  1958. };
  1959. // ------------------------------------------------------------------------------------------------------------
  1960. // v3_funknown
  1961. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  1962. {
  1963. d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface);
  1964. *iface = NULL;
  1965. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  1966. for (const uint8_t* interface_iid : kSupportedInterfaces)
  1967. {
  1968. if (v3_tuid_match(interface_iid, iid))
  1969. {
  1970. *iface = self;
  1971. return V3_OK;
  1972. }
  1973. }
  1974. return V3_NO_INTERFACE;
  1975. };
  1976. ref = []V3_API(void* const self) -> uint32_t
  1977. {
  1978. d_stdout("dpf_message::ref => %p", self);
  1979. dpf_message** const messageptr = static_cast<dpf_message**>(self);
  1980. DISTRHO_SAFE_ASSERT_RETURN(messageptr != nullptr, 0);
  1981. dpf_message* const message = *messageptr;
  1982. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
  1983. return ++message->refcounter;
  1984. };
  1985. unref = []V3_API(void* const self) -> uint32_t
  1986. {
  1987. dpf_message** const messageptr = static_cast<dpf_message**>(self);
  1988. DISTRHO_SAFE_ASSERT_RETURN(messageptr != nullptr, 0);
  1989. dpf_message* const message = *messageptr;
  1990. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
  1991. if (const int refcounter = --message->refcounter)
  1992. return refcounter;
  1993. if (message->attrlist != nullptr)
  1994. dpf_attribute_list_free(message->attrlist->attrs);
  1995. *message->self = nullptr;
  1996. delete messageptr;
  1997. return 0;
  1998. };
  1999. msg.get_message_id = []V3_API(void* const self) -> const char*
  2000. {
  2001. dpf_message* const message = *(dpf_message**)self;
  2002. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
  2003. return message->id;
  2004. };
  2005. msg.set_message_id = []V3_API(void* const self, const char* const id) -> void
  2006. {
  2007. d_stdout("dpf_message::set_message_id => %p %s", self, id);
  2008. dpf_message* const message = *(dpf_message**)self;
  2009. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
  2010. message->id = id;
  2011. };
  2012. msg.get_attributes = []V3_API(void* const self) -> v3_attribute_list**
  2013. {
  2014. dpf_message* const message = *(dpf_message**)self;
  2015. DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
  2016. if (message->attrlist == nullptr)
  2017. message->attrlist = new dpf_attribute_list();
  2018. return (v3_attribute_list**)&message->attrlist;
  2019. };
  2020. }
  2021. };
  2022. v3_message** dpf_message_create(const char* const id)
  2023. {
  2024. ScopedPointer<dpf_message>* const messageptr = new ScopedPointer<dpf_message>;
  2025. *messageptr = new dpf_message(messageptr, id);
  2026. return static_cast<v3_message**>(static_cast<void*>(messageptr));
  2027. }
  2028. #if DISTRHO_PLUGIN_HAS_UI
  2029. // --------------------------------------------------------------------------------------------------------------------
  2030. // dpf_dsp_connection_point
  2031. enum ConnectionPointType {
  2032. kConnectionPointComponent,
  2033. kConnectionPointController,
  2034. kConnectionPointBridge
  2035. };
  2036. struct v3_connection_point_cpp : v3_funknown {
  2037. v3_connection_point point;
  2038. };
  2039. struct dpf_dsp_connection_point : v3_connection_point_cpp {
  2040. ScopedPointer<PluginVst3>& vst3;
  2041. const ConnectionPointType type;
  2042. v3_connection_point** other;
  2043. v3_connection_point** bridge; // when type is controller this points to ctrl<->view point
  2044. bool shortcircuit; // plugin as controller, should pass directly to view
  2045. dpf_dsp_connection_point(const ConnectionPointType t, ScopedPointer<PluginVst3>& v)
  2046. : vst3(v),
  2047. type(t),
  2048. other(nullptr),
  2049. bridge(nullptr),
  2050. shortcircuit(false)
  2051. {
  2052. static const uint8_t* kSupportedInterfaces[] = {
  2053. v3_funknown_iid,
  2054. v3_connection_point_iid
  2055. };
  2056. // ------------------------------------------------------------------------------------------------------------
  2057. // v3_funknown
  2058. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  2059. {
  2060. d_stdout("dpf_dsp_connection_point::query_interface => %p %s %p", self, tuid2str(iid), iface);
  2061. *iface = NULL;
  2062. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  2063. for (const uint8_t* interface_iid : kSupportedInterfaces)
  2064. {
  2065. if (v3_tuid_match(interface_iid, iid))
  2066. {
  2067. *iface = self;
  2068. return V3_OK;
  2069. }
  2070. }
  2071. return V3_NO_INTERFACE;
  2072. };
  2073. // there is only a single instance of this, so we don't have to care here
  2074. ref = []V3_API(void*) -> uint32_t { return 1; };
  2075. unref = []V3_API(void*) -> uint32_t { return 0; };
  2076. // ------------------------------------------------------------------------------------------------------------
  2077. // v3_connection_point
  2078. point.connect = []V3_API(void* self, struct v3_connection_point** other) -> v3_result
  2079. {
  2080. d_stdout("dpf_dsp_connection_point::connect => %p %p", self, other);
  2081. dpf_dsp_connection_point* const point = *(dpf_dsp_connection_point**)self;
  2082. DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED);
  2083. DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG);
  2084. DISTRHO_SAFE_ASSERT(point->bridge == nullptr);
  2085. point->other = other;
  2086. if (point->type == kConnectionPointComponent)
  2087. if (PluginVst3* const vst3 = point->vst3)
  2088. vst3->connect((v3_connection_point**)self);
  2089. return V3_OK;
  2090. };
  2091. point.disconnect = []V3_API(void* self, struct v3_connection_point** other) -> v3_result
  2092. {
  2093. d_stdout("dpf_dsp_connection_point::disconnect => %p %p", self, other);
  2094. dpf_dsp_connection_point* const point = *(dpf_dsp_connection_point**)self;
  2095. DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED);
  2096. DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG);
  2097. point->other = nullptr;
  2098. point->bridge = nullptr;
  2099. if (point->type == kConnectionPointComponent)
  2100. if (PluginVst3* const vst3 = point->vst3)
  2101. vst3->disconnect();
  2102. return V3_OK;
  2103. };
  2104. point.notify = []V3_API(void* self, struct v3_message** message) -> v3_result
  2105. {
  2106. dpf_dsp_connection_point* const point = *(dpf_dsp_connection_point**)self;
  2107. DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED);
  2108. PluginVst3* const vst3 = point->vst3;
  2109. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2110. v3_connection_point** const other = point->other;
  2111. DISTRHO_SAFE_ASSERT_RETURN(other != nullptr, V3_NOT_INITIALISED);
  2112. v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message);
  2113. DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr, V3_INVALID_ARG);
  2114. int64_t target = 0;
  2115. const v3_result res = v3_cpp_obj(attrlist)->get_int(attrlist, "__dpf_msg_target__", &target);
  2116. DISTRHO_SAFE_ASSERT_RETURN(res == V3_OK, res);
  2117. DISTRHO_SAFE_ASSERT_INT_RETURN(target == 1 || target == 2, target, V3_INTERNAL_ERR);
  2118. switch (point->type)
  2119. {
  2120. // message belongs to component (aka plugin)
  2121. case kConnectionPointComponent:
  2122. if (target == 1)
  2123. {
  2124. // view -> edit controller -> component
  2125. return vst3->notify(message);
  2126. }
  2127. else
  2128. {
  2129. // message is from component to controller to view
  2130. return v3_cpp_obj(other)->notify(other, message);
  2131. }
  2132. // message belongs to edit controller
  2133. case kConnectionPointController:
  2134. if (target == 1)
  2135. {
  2136. // we are in view<->dsp short-circuit, all happens in the controller without bridge
  2137. if (point->shortcircuit)
  2138. return vst3->notify(message);
  2139. // view -> edit controller -> component
  2140. return v3_cpp_obj(other)->notify(other, message);
  2141. }
  2142. else
  2143. {
  2144. // we are in view<->dsp short-circuit, all happens in the controller without bridge
  2145. if (point->shortcircuit)
  2146. return v3_cpp_obj(other)->notify(other, message);
  2147. // message is from component to controller to view
  2148. v3_connection_point** const bridge = point->bridge;
  2149. DISTRHO_SAFE_ASSERT_RETURN(bridge != nullptr, V3_NOT_INITIALISED);
  2150. return v3_cpp_obj(bridge)->notify(bridge, message);
  2151. }
  2152. // message belongs to bridge (aka ui)
  2153. case kConnectionPointBridge:
  2154. if (target == 1)
  2155. {
  2156. // view -> edit controller -> component
  2157. v3_connection_point** const bridge = point->bridge;
  2158. DISTRHO_SAFE_ASSERT_RETURN(bridge != nullptr, V3_NOT_INITIALISED);
  2159. return v3_cpp_obj(bridge)->notify(bridge, message);
  2160. }
  2161. else
  2162. {
  2163. // message is from component to controller to view
  2164. return v3_cpp_obj(other)->notify(other, message);
  2165. }
  2166. }
  2167. return V3_INTERNAL_ERR;
  2168. };
  2169. }
  2170. };
  2171. #endif
  2172. // --------------------------------------------------------------------------------------------------------------------
  2173. // dpf_edit_controller
  2174. struct v3_edit_controller_cpp : v3_funknown {
  2175. v3_plugin_base base;
  2176. v3_edit_controller controller;
  2177. };
  2178. struct dpf_edit_controller : v3_edit_controller_cpp {
  2179. #if DISTRHO_PLUGIN_HAS_UI
  2180. ScopedPointer<dpf_dsp_connection_point> connectionComp; // kConnectionPointController
  2181. ScopedPointer<dpf_dsp_connection_point> connectionBridge; // kConnectionPointBridge
  2182. #endif
  2183. ScopedPointer<PluginVst3>& vst3;
  2184. bool initialized;
  2185. // cached values
  2186. v3_component_handler** handler;
  2187. dpf_edit_controller(ScopedPointer<PluginVst3>& v)
  2188. : vst3(v),
  2189. initialized(false),
  2190. handler(nullptr)
  2191. {
  2192. static const uint8_t* kSupportedInterfacesBase[] = {
  2193. v3_funknown_iid,
  2194. v3_edit_controller_iid
  2195. };
  2196. // ------------------------------------------------------------------------------------------------------------
  2197. // v3_funknown
  2198. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  2199. {
  2200. d_stdout("dpf_edit_controller::query_interface => %p %s %p", self, tuid2str(iid), iface);
  2201. *iface = NULL;
  2202. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  2203. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  2204. {
  2205. if (v3_tuid_match(interface_iid, iid))
  2206. {
  2207. *iface = self;
  2208. return V3_OK;
  2209. }
  2210. }
  2211. #if DISTRHO_PLUGIN_HAS_UI
  2212. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2213. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NO_INTERFACE);
  2214. if (v3_tuid_match(v3_connection_point_iid, iid))
  2215. {
  2216. if (controller->connectionComp == nullptr)
  2217. controller->connectionComp = new dpf_dsp_connection_point(kConnectionPointController,
  2218. controller->vst3);
  2219. *iface = &controller->connectionComp;
  2220. return V3_OK;
  2221. }
  2222. #endif
  2223. return V3_NO_INTERFACE;
  2224. };
  2225. // there is only a single instance of this, so we don't have to care here
  2226. ref = []V3_API(void*) -> uint32_t { return 1; };
  2227. unref = []V3_API(void*) -> uint32_t { return 0; };
  2228. // ------------------------------------------------------------------------------------------------------------
  2229. // v3_plugin_base
  2230. base.initialise = []V3_API(void* self, struct v3_plugin_base::v3_funknown *context) -> v3_result
  2231. {
  2232. d_stdout("dpf_edit_controller::initialise => %p %p", self, context);
  2233. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2234. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2235. const bool initialized = controller->initialized;
  2236. DISTRHO_SAFE_ASSERT_RETURN(! initialized, V3_INVALID_ARG);
  2237. controller->initialized = true;
  2238. return V3_OK;
  2239. };
  2240. base.terminate = []V3_API(void* self) -> v3_result
  2241. {
  2242. d_stdout("dpf_edit_controller::terminate => %p", self);
  2243. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2244. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2245. const bool initialized = controller->initialized;
  2246. DISTRHO_SAFE_ASSERT_RETURN(initialized, V3_INVALID_ARG);
  2247. controller->initialized = false;
  2248. return V3_OK;
  2249. };
  2250. // ------------------------------------------------------------------------------------------------------------
  2251. // v3_edit_controller
  2252. controller.set_component_state = []V3_API(void* self, v3_bstream* stream) -> v3_result
  2253. {
  2254. d_stdout("dpf_edit_controller::set_component_state => %p %p", self, stream);
  2255. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2256. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2257. PluginVst3* const vst3 = controller->vst3;
  2258. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2259. #if 0
  2260. return vst3->setComponentState(stream);
  2261. #endif
  2262. // TODO, returning ok to make renoise happy
  2263. return V3_OK;
  2264. };
  2265. controller.set_state = []V3_API(void* self, v3_bstream* stream) -> v3_result
  2266. {
  2267. d_stdout("dpf_edit_controller::set_state => %p %p", self, stream);
  2268. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2269. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2270. PluginVst3* const vst3 = controller->vst3;
  2271. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2272. #if 0
  2273. return vst3->setState(stream);
  2274. #endif
  2275. return V3_NOT_IMPLEMENTED;
  2276. };
  2277. controller.get_state = []V3_API(void* self, v3_bstream* stream) -> v3_result
  2278. {
  2279. d_stdout("dpf_edit_controller::get_state => %p %p", self, stream);
  2280. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2281. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2282. PluginVst3* const vst3 = controller->vst3;
  2283. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2284. #if 0
  2285. return vst3->getState(stream);
  2286. #endif
  2287. return V3_NOT_IMPLEMENTED;
  2288. };
  2289. controller.get_parameter_count = []V3_API(void* self) -> int32_t
  2290. {
  2291. // d_stdout("dpf_edit_controller::get_parameter_count => %p", self);
  2292. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2293. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2294. PluginVst3* const vst3 = controller->vst3;
  2295. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2296. return vst3->getParameterCount();
  2297. };
  2298. controller.get_parameter_info = []V3_API(void* self, int32_t param_idx, v3_param_info* param_info) -> v3_result
  2299. {
  2300. // d_stdout("dpf_edit_controller::get_parameter_info => %p %i", self, param_idx);
  2301. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2302. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2303. PluginVst3* const vst3 = controller->vst3;
  2304. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2305. return vst3->getParameterInfo(param_idx, param_info);
  2306. };
  2307. controller.get_parameter_string_for_value = []V3_API(void* self, v3_param_id index, double normalised, v3_str_128 output) -> v3_result
  2308. {
  2309. // NOTE very noisy, called many times
  2310. // d_stdout("dpf_edit_controller::get_parameter_string_for_value => %p %u %f %p", self, index, normalised, output);
  2311. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2312. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2313. PluginVst3* const vst3 = controller->vst3;
  2314. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2315. return vst3->getParameterStringForValue(index, normalised, output);
  2316. };
  2317. controller.get_parameter_value_for_string = []V3_API(void* self, v3_param_id index, int16_t* input, double* output) -> v3_result
  2318. {
  2319. d_stdout("dpf_edit_controller::get_parameter_value_for_string => %p %u %p %p", self, index, input, output);
  2320. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2321. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2322. PluginVst3* const vst3 = controller->vst3;
  2323. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2324. return vst3->getParameterValueForString(index, input, output);
  2325. };
  2326. controller.normalised_parameter_to_plain = []V3_API(void* self, v3_param_id index, double normalised) -> double
  2327. {
  2328. d_stdout("dpf_edit_controller::normalised_parameter_to_plain => %p %u %f", self, index, normalised);
  2329. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2330. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2331. PluginVst3* const vst3 = controller->vst3;
  2332. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2333. return vst3->normalisedParameterToPlain(index, normalised);
  2334. };
  2335. controller.plain_parameter_to_normalised = []V3_API(void* self, v3_param_id index, double plain) -> double
  2336. {
  2337. d_stdout("dpf_edit_controller::plain_parameter_to_normalised => %p %u %f", self, index, plain);
  2338. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2339. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2340. PluginVst3* const vst3 = controller->vst3;
  2341. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2342. return vst3->plainParameterToNormalised(index, plain);
  2343. };
  2344. controller.get_parameter_normalised = []V3_API(void* self, v3_param_id index) -> double
  2345. {
  2346. // NOTE very noisy, called many times
  2347. // d_stdout("dpf_edit_controller::get_parameter_normalised => %p %u", self, index);
  2348. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2349. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0.0);
  2350. PluginVst3* const vst3 = controller->vst3;
  2351. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0.0);
  2352. return vst3->getParameterNormalized(index);
  2353. };
  2354. controller.set_parameter_normalised = []V3_API(void* self, v3_param_id index, double normalised) -> v3_result
  2355. {
  2356. d_stdout("dpf_edit_controller::set_parameter_normalised => %p %u %f", self, index, normalised);
  2357. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2358. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2359. PluginVst3* const vst3 = controller->vst3;
  2360. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2361. return vst3->setParameterNormalized(index, normalised);
  2362. };
  2363. controller.set_component_handler = []V3_API(void* self, v3_component_handler** handler) -> v3_result
  2364. {
  2365. d_stdout("dpf_edit_controller::set_component_handler => %p %p", self, handler);
  2366. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2367. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
  2368. controller->handler = handler;
  2369. if (PluginVst3* const vst3 = controller->vst3)
  2370. return vst3->setComponentHandler(handler);
  2371. return V3_NOT_INITIALISED;
  2372. };
  2373. controller.create_view = []V3_API(void* self, const char* name) -> v3_plugin_view**
  2374. {
  2375. d_stdout("dpf_edit_controller::create_view => %p %s", self, name);
  2376. dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
  2377. DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr);
  2378. #if DISTRHO_PLUGIN_HAS_UI
  2379. PluginVst3* const vst3 = controller->vst3;
  2380. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr);
  2381. // if there is a component connection, we require it to be active
  2382. if (controller->connectionComp != nullptr)
  2383. {
  2384. DISTRHO_SAFE_ASSERT_RETURN(controller->connectionComp->other != nullptr, nullptr);
  2385. }
  2386. // otherwise short-circuit and deal with this ourselves (assume local usage)
  2387. else
  2388. {
  2389. controller->connectionComp = new dpf_dsp_connection_point(kConnectionPointController,
  2390. controller->vst3);
  2391. controller->connectionComp->shortcircuit = true;
  2392. }
  2393. v3_plugin_view** const view = dpf_plugin_view_create(vst3->getInstancePointer(),
  2394. vst3->getSampleRate());
  2395. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, nullptr);
  2396. v3_connection_point** uiconn = nullptr;
  2397. if (v3_cpp_obj_query_interface(view, v3_connection_point_iid, &uiconn) == V3_OK)
  2398. {
  2399. d_stdout("view connection query ok %p | shortcircuit %d",
  2400. uiconn, controller->connectionComp->shortcircuit);
  2401. v3_connection_point** const ctrlconn = (v3_connection_point**)&controller->connectionComp;
  2402. if (controller->connectionComp->shortcircuit)
  2403. {
  2404. vst3->disconnect();
  2405. v3_cpp_obj(uiconn)->connect(uiconn, ctrlconn);
  2406. v3_cpp_obj(ctrlconn)->connect(ctrlconn, uiconn);
  2407. vst3->connect(ctrlconn);
  2408. }
  2409. else
  2410. {
  2411. controller->connectionBridge = new dpf_dsp_connection_point(kConnectionPointBridge,
  2412. controller->vst3);
  2413. v3_connection_point** const bridgeconn = (v3_connection_point**)&controller->connectionBridge;
  2414. v3_cpp_obj(uiconn)->connect(uiconn, bridgeconn);
  2415. v3_cpp_obj(bridgeconn)->connect(bridgeconn, uiconn);
  2416. controller->connectionComp->bridge = bridgeconn;
  2417. controller->connectionBridge->bridge = ctrlconn;
  2418. }
  2419. }
  2420. return view;
  2421. #else
  2422. return nullptr;
  2423. #endif
  2424. };
  2425. }
  2426. };
  2427. // --------------------------------------------------------------------------------------------------------------------
  2428. // dpf_process_context_requirements
  2429. struct v3_process_context_requirements_cpp : v3_funknown {
  2430. v3_process_context_requirements req;
  2431. };
  2432. struct dpf_process_context_requirements : v3_process_context_requirements_cpp {
  2433. dpf_process_context_requirements()
  2434. {
  2435. static const uint8_t* kSupportedInterfaces[] = {
  2436. v3_funknown_iid,
  2437. v3_process_context_requirements_iid
  2438. };
  2439. // ------------------------------------------------------------------------------------------------------------
  2440. // v3_funknown
  2441. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  2442. {
  2443. d_stdout("dpf_process_context_requirements::query_interface => %p %s %p", self, tuid2str(iid), iface);
  2444. *iface = NULL;
  2445. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  2446. for (const uint8_t* interface_iid : kSupportedInterfaces)
  2447. {
  2448. if (v3_tuid_match(interface_iid, iid))
  2449. {
  2450. *iface = self;
  2451. return V3_OK;
  2452. }
  2453. }
  2454. return V3_NO_INTERFACE;
  2455. };
  2456. // this is used statically, so we don't have to care here
  2457. ref = []V3_API(void*) -> uint32_t { return 1; };
  2458. unref = []V3_API(void*) -> uint32_t { return 0; };
  2459. // ------------------------------------------------------------------------------------------------------------
  2460. // v3_process_context_requirements
  2461. req.get_process_context_requirements = []V3_API(void*) -> uint32_t
  2462. {
  2463. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  2464. return 0x0
  2465. |V3_PROCESS_CTX_NEED_CONTINUOUS_TIME // V3_PROCESS_CTX_CONT_TIME_VALID
  2466. |V3_PROCESS_CTX_NEED_PROJECT_TIME // V3_PROCESS_CTX_PROJECT_TIME_VALID
  2467. |V3_PROCESS_CTX_NEED_TEMPO // V3_PROCESS_CTX_TEMPO_VALID
  2468. |V3_PROCESS_CTX_NEED_TIME_SIG // V3_PROCESS_CTX_TIME_SIG_VALID
  2469. |V3_PROCESS_CTX_NEED_TRANSPORT_STATE; // V3_PROCESS_CTX_PLAYING
  2470. #else
  2471. return 0x0;
  2472. #endif
  2473. };
  2474. }
  2475. DISTRHO_PREVENT_HEAP_ALLOCATION
  2476. };
  2477. // --------------------------------------------------------------------------------------------------------------------
  2478. // dpf_audio_processor
  2479. struct v3_audio_processor_cpp : v3_funknown {
  2480. v3_audio_processor processor;
  2481. };
  2482. struct dpf_audio_processor : v3_audio_processor_cpp {
  2483. ScopedPointer<PluginVst3>& vst3;
  2484. dpf_audio_processor(ScopedPointer<PluginVst3>& v)
  2485. : vst3(v)
  2486. {
  2487. static const uint8_t* kSupportedInterfacesBase[] = {
  2488. v3_funknown_iid,
  2489. v3_audio_processor_iid
  2490. };
  2491. // ------------------------------------------------------------------------------------------------------------
  2492. // v3_funknown
  2493. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  2494. {
  2495. d_stdout("dpf_audio_processor::query_interface => %p %s %p", self, tuid2str(iid), iface);
  2496. *iface = NULL;
  2497. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  2498. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  2499. {
  2500. if (v3_tuid_match(interface_iid, iid))
  2501. {
  2502. *iface = self;
  2503. return V3_OK;
  2504. }
  2505. }
  2506. if (v3_tuid_match(v3_process_context_requirements_iid, iid))
  2507. {
  2508. static dpf_process_context_requirements context_req;
  2509. static dpf_process_context_requirements* context_req_ptr = &context_req;;
  2510. *iface = &context_req_ptr;
  2511. return V3_OK;
  2512. }
  2513. return V3_NO_INTERFACE;
  2514. };
  2515. // there is only a single instance of this, so we don't have to care here
  2516. ref = []V3_API(void*) -> uint32_t { return 1; };
  2517. unref = []V3_API(void*) -> uint32_t { return 0; };
  2518. // ------------------------------------------------------------------------------------------------------------
  2519. // v3_audio_processor
  2520. processor.set_bus_arrangements = []V3_API(void* self,
  2521. v3_speaker_arrangement* inputs, int32_t num_inputs,
  2522. v3_speaker_arrangement* outputs, int32_t num_outputs) -> v3_result
  2523. {
  2524. // NOTE this is called a bunch of times
  2525. // d_stdout("dpf_audio_processor::set_bus_arrangements => %p %p %i %p %i", self, inputs, num_inputs, outputs, num_outputs);
  2526. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2527. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  2528. PluginVst3* const vst3 = processor->vst3;
  2529. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2530. return processor->vst3->setBusArrangements(inputs, num_inputs, outputs, num_outputs);
  2531. };
  2532. processor.get_bus_arrangement = []V3_API(void* self, int32_t bus_direction,
  2533. int32_t idx, v3_speaker_arrangement* arr) -> v3_result
  2534. {
  2535. d_stdout("dpf_audio_processor::get_bus_arrangement => %p %i %i %p", self, bus_direction, idx, arr);
  2536. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2537. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  2538. PluginVst3* const vst3 = processor->vst3;
  2539. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2540. return processor->vst3->getBusArrangement(bus_direction, idx, arr);
  2541. };
  2542. processor.can_process_sample_size = []V3_API(void* self, int32_t symbolic_sample_size) -> v3_result
  2543. {
  2544. d_stdout("dpf_audio_processor::can_process_sample_size => %p %i", self, symbolic_sample_size);
  2545. return symbolic_sample_size == V3_SAMPLE_32 ? V3_OK : V3_NOT_IMPLEMENTED;
  2546. };
  2547. processor.get_latency_samples = []V3_API(void* self) -> uint32_t
  2548. {
  2549. d_stdout("dpf_audio_processor::get_latency_samples => %p", self);
  2550. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2551. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0);
  2552. PluginVst3* const vst3 = processor->vst3;
  2553. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0);
  2554. return processor->vst3->getLatencySamples();
  2555. };
  2556. processor.setup_processing = []V3_API(void* self, v3_process_setup* setup) -> v3_result
  2557. {
  2558. d_stdout("dpf_audio_processor::setup_processing => %p", self);
  2559. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2560. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  2561. PluginVst3* const vst3 = processor->vst3;
  2562. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2563. d_lastBufferSize = setup->max_block_size;
  2564. d_lastSampleRate = setup->sample_rate;
  2565. return processor->vst3->setupProcessing(setup);
  2566. };
  2567. processor.set_processing = []V3_API(void* self, v3_bool state) -> v3_result
  2568. {
  2569. d_stdout("dpf_audio_processor::set_processing => %p %u", self, state);
  2570. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2571. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  2572. PluginVst3* const vst3 = processor->vst3;
  2573. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2574. return processor->vst3->setProcessing(state);
  2575. };
  2576. processor.process = []V3_API(void* self, v3_process_data* data) -> v3_result
  2577. {
  2578. // NOTE runs during RT
  2579. // d_stdout("dpf_audio_processor::process => %p", self);
  2580. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2581. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED);
  2582. PluginVst3* const vst3 = processor->vst3;
  2583. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2584. return processor->vst3->process(data);
  2585. };
  2586. processor.get_tail_samples = []V3_API(void* self) -> uint32_t
  2587. {
  2588. d_stdout("dpf_audio_processor::get_tail_samples => %p", self);
  2589. dpf_audio_processor* const processor = *(dpf_audio_processor**)self;
  2590. DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0);
  2591. PluginVst3* const vst3 = processor->vst3;
  2592. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0);
  2593. return processor->vst3->getTailSamples();
  2594. };
  2595. }
  2596. };
  2597. // --------------------------------------------------------------------------------------------------------------------
  2598. // dpf_component
  2599. struct v3_component_cpp : v3_funknown {
  2600. v3_plugin_base base;
  2601. v3_component comp;
  2602. };
  2603. struct dpf_component : v3_component_cpp {
  2604. std::atomic<int> refcounter;
  2605. ScopedPointer<dpf_component>* self;
  2606. ScopedPointer<dpf_audio_processor> processor;
  2607. #if DISTRHO_PLUGIN_HAS_UI
  2608. ScopedPointer<dpf_dsp_connection_point> connection; // kConnectionPointComponent
  2609. #endif
  2610. ScopedPointer<dpf_edit_controller> controller;
  2611. ScopedPointer<PluginVst3> vst3;
  2612. dpf_component(ScopedPointer<dpf_component>* const s)
  2613. : refcounter(1),
  2614. self(s)
  2615. {
  2616. static const uint8_t* kSupportedInterfacesBase[] = {
  2617. v3_funknown_iid,
  2618. v3_plugin_base_iid,
  2619. v3_component_iid
  2620. };
  2621. // ------------------------------------------------------------------------------------------------------------
  2622. // v3_funknown
  2623. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  2624. {
  2625. d_stdout("dpf_component::query_interface => %p %s %p", self, tuid2str(iid), iface);
  2626. *iface = NULL;
  2627. for (const uint8_t* interface_iid : kSupportedInterfacesBase)
  2628. {
  2629. if (v3_tuid_match(interface_iid, iid))
  2630. {
  2631. *iface = self;
  2632. return V3_OK;
  2633. }
  2634. }
  2635. dpf_component* const component = *(dpf_component**)self;
  2636. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NO_INTERFACE);
  2637. if (v3_tuid_match(v3_audio_processor_iid, iid))
  2638. {
  2639. if (component->processor == nullptr)
  2640. component->processor = new dpf_audio_processor(component->vst3);
  2641. *iface = &component->processor;
  2642. return V3_OK;
  2643. }
  2644. #if DISTRHO_PLUGIN_HAS_UI
  2645. if (v3_tuid_match(v3_connection_point_iid, iid))
  2646. {
  2647. if (component->connection == nullptr)
  2648. component->connection = new dpf_dsp_connection_point(kConnectionPointComponent,
  2649. component->vst3);
  2650. *iface = &component->connection;
  2651. return V3_OK;
  2652. }
  2653. #endif
  2654. if (v3_tuid_match(v3_edit_controller_iid, iid))
  2655. {
  2656. if (component->controller == nullptr)
  2657. component->controller = new dpf_edit_controller(component->vst3);
  2658. *iface = &component->controller;
  2659. return V3_OK;
  2660. }
  2661. return V3_NO_INTERFACE;
  2662. };
  2663. #if 1
  2664. // TODO fix this up later
  2665. ref = []V3_API(void*) -> uint32_t { return 1; };
  2666. unref = []V3_API(void*) -> uint32_t { return 0; };
  2667. #else
  2668. ref = []V3_API(void* self) -> uint32_t
  2669. {
  2670. d_stdout("dpf_component::ref => %p", self);
  2671. dpf_component* const component = *(dpf_component**)self;
  2672. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, 0);
  2673. return ++component->refcounter;
  2674. };
  2675. unref = []V3_API(void* self) -> uint32_t
  2676. {
  2677. d_stdout("dpf_component::unref => %p", self);
  2678. dpf_component* const component = *(dpf_component**)self;
  2679. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, 0);
  2680. if (const int refcount = --component->refcounter)
  2681. {
  2682. d_stdout("dpf_component::unref => %p | refcount %i", self, refcount);
  2683. return refcount;
  2684. }
  2685. d_stdout("dpf_component::unref => %p | refcount is zero, deleting everything now!", self);
  2686. *component->self = nullptr;
  2687. delete (dpf_component**)self;
  2688. return 0;
  2689. };
  2690. #endif
  2691. // ------------------------------------------------------------------------------------------------------------
  2692. // v3_plugin_base
  2693. base.initialise = []V3_API(void* self, struct v3_plugin_base::v3_funknown* context) -> v3_result
  2694. {
  2695. d_stdout("dpf_component::initialise => %p %p", self, context);
  2696. dpf_component* const component = *(dpf_component**)self;
  2697. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2698. PluginVst3* const vst3 = component->vst3;
  2699. DISTRHO_SAFE_ASSERT_RETURN(vst3 == nullptr, V3_INVALID_ARG);
  2700. d_lastCanRequestParameterValueChanges = true;
  2701. // default early values
  2702. if (d_lastBufferSize == 0)
  2703. d_lastBufferSize = 2048;
  2704. if (d_lastSampleRate <= 0.0)
  2705. d_lastSampleRate = 44100.0;
  2706. component->vst3 = new PluginVst3();
  2707. return V3_OK;
  2708. };
  2709. base.terminate = []V3_API(void* self) -> v3_result
  2710. {
  2711. d_stdout("dpf_component::terminate => %p", self);
  2712. dpf_component* const component = *(dpf_component**)self;
  2713. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2714. PluginVst3* const vst3 = component->vst3;
  2715. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_INVALID_ARG);
  2716. component->vst3 = nullptr;
  2717. return V3_OK;
  2718. };
  2719. // ------------------------------------------------------------------------------------------------------------
  2720. // v3_component
  2721. comp.get_controller_class_id = []V3_API(void* self, v3_tuid class_id) -> v3_result
  2722. {
  2723. d_stdout("dpf_component::get_controller_class_id => %p %s", self, tuid2str(class_id));
  2724. dpf_component* const component = *(dpf_component**)self;
  2725. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2726. PluginVst3* const vst3 = component->vst3;
  2727. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2728. // TODO
  2729. return V3_NOT_IMPLEMENTED;
  2730. };
  2731. comp.set_io_mode = []V3_API(void* self, int32_t io_mode) -> v3_result
  2732. {
  2733. d_stdout("dpf_component::set_io_mode => %p %i", self, io_mode);
  2734. dpf_component* const component = *(dpf_component**)self;
  2735. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2736. PluginVst3* const vst3 = component->vst3;
  2737. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2738. // TODO
  2739. return V3_NOT_IMPLEMENTED;
  2740. };
  2741. comp.get_bus_count = []V3_API(void* self, int32_t media_type, int32_t bus_direction) -> int32_t
  2742. {
  2743. // NOTE runs during RT
  2744. // d_stdout("dpf_component::get_bus_count => %p %i %i", self, media_type, bus_direction);
  2745. dpf_component* const component = *(dpf_component**)self;
  2746. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2747. PluginVst3* const vst3 = component->vst3;
  2748. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2749. return vst3->getBusCount(media_type, bus_direction);
  2750. };
  2751. comp.get_bus_info = []V3_API(void* self, int32_t media_type, int32_t bus_direction,
  2752. int32_t bus_idx, v3_bus_info* info) -> v3_result
  2753. {
  2754. d_stdout("dpf_component::get_bus_info => %p %i %i %i %p", self, media_type, bus_direction, bus_idx, info);
  2755. dpf_component* const component = *(dpf_component**)self;
  2756. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2757. PluginVst3* const vst3 = component->vst3;
  2758. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2759. return vst3->getBusInfo(media_type, bus_direction, bus_idx, info);
  2760. };
  2761. comp.get_routing_info = []V3_API(void* self, v3_routing_info* input, v3_routing_info* output) -> v3_result
  2762. {
  2763. d_stdout("dpf_component::get_routing_info => %p %p %p", self, input, output);
  2764. dpf_component* const component = *(dpf_component**)self;
  2765. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2766. PluginVst3* const vst3 = component->vst3;
  2767. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2768. return vst3->getRoutingInfo(input, output);
  2769. };
  2770. comp.activate_bus = []V3_API(void* self, int32_t media_type, int32_t bus_direction,
  2771. int32_t bus_idx, v3_bool state) -> v3_result
  2772. {
  2773. // NOTE this is called a bunch of times
  2774. // d_stdout("dpf_component::activate_bus => %p %i %i %i %u", self, media_type, bus_direction, bus_idx, state);
  2775. dpf_component* const component = *(dpf_component**)self;
  2776. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2777. PluginVst3* const vst3 = component->vst3;
  2778. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2779. return vst3->activateBus(media_type, bus_direction, bus_idx, state);
  2780. };
  2781. comp.set_active = []V3_API(void* self, v3_bool state) -> v3_result
  2782. {
  2783. d_stdout("dpf_component::set_active => %p %u", self, state);
  2784. dpf_component* const component = *(dpf_component**)self;
  2785. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2786. PluginVst3* const vst3 = component->vst3;
  2787. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2788. return component->vst3->setActive(state);
  2789. };
  2790. comp.set_state = []V3_API(void* self, v3_bstream** stream) -> v3_result
  2791. {
  2792. d_stdout("dpf_component::set_state => %p", self);
  2793. dpf_component* const component = *(dpf_component**)self;
  2794. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2795. PluginVst3* const vst3 = component->vst3;
  2796. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2797. return vst3->setState(stream);
  2798. };
  2799. comp.get_state = []V3_API(void* self, v3_bstream** stream) -> v3_result
  2800. {
  2801. d_stdout("dpf_component::get_state => %p %p", self, stream);
  2802. dpf_component* const component = *(dpf_component**)self;
  2803. DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED);
  2804. PluginVst3* const vst3 = component->vst3;
  2805. DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
  2806. return vst3->getState(stream);
  2807. };
  2808. }
  2809. };
  2810. // --------------------------------------------------------------------------------------------------------------------
  2811. // dpf_factory
  2812. struct v3_plugin_factory_cpp : v3_funknown {
  2813. v3_plugin_factory v1;
  2814. v3_plugin_factory_2 v2;
  2815. v3_plugin_factory_3 v3;
  2816. };
  2817. struct dpf_factory : v3_plugin_factory_cpp {
  2818. std::vector<ScopedPointer<dpf_component>*> components;
  2819. dpf_factory()
  2820. {
  2821. static const uint8_t* kSupportedFactories[] = {
  2822. v3_funknown_iid,
  2823. v3_plugin_factory_iid,
  2824. v3_plugin_factory_2_iid,
  2825. v3_plugin_factory_3_iid
  2826. };
  2827. // ------------------------------------------------------------------------------------------------------------
  2828. // Dummy plugin to get data from
  2829. d_lastBufferSize = 512;
  2830. d_lastSampleRate = 44100.0;
  2831. d_lastCanRequestParameterValueChanges = true;
  2832. static const PluginExporter gPluginInfo(nullptr, nullptr, nullptr);
  2833. d_lastBufferSize = 0;
  2834. d_lastSampleRate = 0.0;
  2835. d_lastCanRequestParameterValueChanges = false;
  2836. dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2]
  2837. = dpf_tuid_processor[2] = dpf_tuid_view[2] = gPluginInfo.getUniqueId();
  2838. // ------------------------------------------------------------------------------------------------------------
  2839. // v3_funknown
  2840. query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
  2841. {
  2842. d_stdout("dpf_factory::query_interface => %p %s %p", self, tuid2str(iid), iface);
  2843. *iface = NULL;
  2844. DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
  2845. for (const uint8_t* factory_iid : kSupportedFactories)
  2846. {
  2847. if (v3_tuid_match(factory_iid, iid))
  2848. {
  2849. *iface = self;
  2850. return V3_OK;
  2851. }
  2852. }
  2853. return V3_NO_INTERFACE;
  2854. };
  2855. // we only support 1 plugin per binary, so don't have to care here
  2856. ref = []V3_API(void*) -> uint32_t { return 1; };
  2857. unref = []V3_API(void*) -> uint32_t { return 0; };
  2858. // ------------------------------------------------------------------------------------------------------------
  2859. // v3_plugin_factory
  2860. v1.get_factory_info = []V3_API(void*, struct v3_factory_info* const info) -> v3_result
  2861. {
  2862. std::memset(info, 0, sizeof(*info));
  2863. DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo.getMaker(), sizeof(info->vendor));
  2864. DISTRHO_NAMESPACE::strncpy(info->url, gPluginInfo.getHomePage(), sizeof(info->url));
  2865. // DISTRHO_NAMESPACE::strncpy(info->email, "", sizeof(info->email)); // TODO
  2866. return V3_OK;
  2867. };
  2868. v1.num_classes = []V3_API(void*) -> int32_t
  2869. {
  2870. return 1;
  2871. };
  2872. v1.get_class_info = []V3_API(void*, int32_t idx, struct v3_class_info* const info) -> v3_result
  2873. {
  2874. std::memset(info, 0, sizeof(*info));
  2875. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  2876. std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  2877. info->cardinality = 0x7FFFFFFF;
  2878. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
  2879. DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo.getName(), sizeof(info->name));
  2880. return V3_OK;
  2881. };
  2882. v1.create_instance = []V3_API(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance) -> v3_result
  2883. {
  2884. d_stdout("dpf_factory::create_instance => %p %s %s %p", self, tuid2str(class_id), tuid2str(iid), instance);
  2885. DISTRHO_SAFE_ASSERT_RETURN(v3_tuid_match(class_id, *(v3_tuid*)&dpf_tuid_class) &&
  2886. v3_tuid_match(iid, v3_component_iid), V3_NO_INTERFACE);
  2887. dpf_factory* const factory = *(dpf_factory**)self;
  2888. DISTRHO_SAFE_ASSERT_RETURN(factory != nullptr, V3_NOT_INITIALISED);
  2889. ScopedPointer<dpf_component>* const componentptr = new ScopedPointer<dpf_component>;
  2890. *componentptr = new dpf_component(componentptr);
  2891. *instance = componentptr;
  2892. factory->components.push_back(componentptr);
  2893. return V3_OK;
  2894. };
  2895. // ------------------------------------------------------------------------------------------------------------
  2896. // v3_plugin_factory_2
  2897. v2.get_class_info_2 = []V3_API(void*, int32_t idx, struct v3_class_info_2* info) -> v3_result
  2898. {
  2899. std::memset(info, 0, sizeof(*info));
  2900. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  2901. std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  2902. info->cardinality = 0x7FFFFFFF;
  2903. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category));
  2904. DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo.getName(), ARRAY_SIZE(info->name));
  2905. info->class_flags = 0;
  2906. // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO
  2907. DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo.getMaker(), ARRAY_SIZE(info->vendor));
  2908. DISTRHO_NAMESPACE::snprintf_u32(info->version, gPluginInfo.getVersion(), ARRAY_SIZE(info->version)); // FIXME
  2909. DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ?
  2910. return V3_OK;
  2911. };
  2912. // ------------------------------------------------------------------------------------------------------------
  2913. // v3_plugin_factory_3
  2914. v3.get_class_info_utf16 = []V3_API(void*, int32_t idx, struct v3_class_info_3* info) -> v3_result
  2915. {
  2916. std::memset(info, 0, sizeof(*info));
  2917. DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE);
  2918. std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
  2919. info->cardinality = 0x7FFFFFFF;
  2920. DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category));
  2921. DISTRHO_NAMESPACE::strncpy_utf16(info->name, gPluginInfo.getName(), ARRAY_SIZE(info->name));
  2922. info->class_flags = 0;
  2923. // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", ARRAY_SIZE(info->sub_categories)); // TODO
  2924. DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, gPluginInfo.getMaker(), sizeof(info->vendor));
  2925. DISTRHO_NAMESPACE::snprintf_u32_utf16(info->version, gPluginInfo.getVersion(), ARRAY_SIZE(info->version)); // FIXME
  2926. DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ?
  2927. return V3_OK;
  2928. };
  2929. v3.set_host_context = []V3_API (void* self, struct v3_funknown* host) -> v3_result
  2930. {
  2931. d_stdout("dpf_factory::set_host_context => %p %p", self, host);
  2932. return V3_NOT_IMPLEMENTED;
  2933. };
  2934. }
  2935. ~dpf_factory()
  2936. {
  2937. d_stdout("dpf_factory deleting");
  2938. for (ScopedPointer<dpf_component>* componentptr : components)
  2939. {
  2940. *componentptr = nullptr;
  2941. delete componentptr;
  2942. }
  2943. }
  2944. DISTRHO_PREVENT_HEAP_ALLOCATION
  2945. };
  2946. END_NAMESPACE_DISTRHO
  2947. // --------------------------------------------------------------------------------------------------------------------
  2948. // VST3 entry point
  2949. DISTRHO_PLUGIN_EXPORT
  2950. const void* GetPluginFactory(void);
  2951. const void* GetPluginFactory(void)
  2952. {
  2953. USE_NAMESPACE_DISTRHO;
  2954. static const dpf_factory factory;
  2955. static const v3_funknown* const factoryptr = &factory;
  2956. return &factoryptr;
  2957. }
  2958. // --------------------------------------------------------------------------------------------------------------------
  2959. // OS specific module load
  2960. #if defined(DISTRHO_OS_MAC)
  2961. # define ENTRYFNNAME bundleEntry
  2962. # define EXITFNNAME bundleExit
  2963. #elif defined(DISTRHO_OS_WINDOWS)
  2964. # define ENTRYFNNAME InitDll
  2965. # define EXITFNNAME ExitDll
  2966. #else
  2967. # define ENTRYFNNAME ModuleEntry
  2968. # define EXITFNNAME ModuleExit
  2969. #endif
  2970. DISTRHO_PLUGIN_EXPORT
  2971. bool ENTRYFNNAME(void*);
  2972. bool ENTRYFNNAME(void*)
  2973. {
  2974. return true;
  2975. }
  2976. DISTRHO_PLUGIN_EXPORT
  2977. bool EXITFNNAME(void);
  2978. bool EXITFNNAME(void)
  2979. {
  2980. return true;
  2981. }
  2982. #undef ENTRYFNNAME
  2983. #undef EXITFNNAME
  2984. // --------------------------------------------------------------------------------------------------------------------