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.

237 lines
6.0KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 3 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #ifndef PLUGIN_MODEL
  18. # error PLUGIN_MODEL undefined
  19. #endif
  20. #ifndef PLUGIN_CV_INPUTS
  21. # error PLUGIN_CV_INPUTS undefined
  22. #endif
  23. #ifndef PLUGIN_CV_OUTPUTS
  24. # error PLUGIN_CV_OUTPUTS undefined
  25. #endif
  26. static constexpr const bool kCvInputs[] = PLUGIN_CV_INPUTS;
  27. static constexpr const bool kCvOutputs[] = PLUGIN_CV_OUTPUTS;
  28. #include "src/lv2/buf-size.h"
  29. #include "src/lv2/options.h"
  30. #include "DistrhoUtils.hpp"
  31. #include <time.h>
  32. #include <sys/time.h>
  33. namespace rack {
  34. static thread_local Context* threadContext = nullptr;
  35. Context* contextGet() {
  36. DISTRHO_SAFE_ASSERT(threadContext != nullptr);
  37. return threadContext;
  38. }
  39. #ifdef ARCH_MAC
  40. __attribute__((optnone))
  41. #endif
  42. void contextSet(Context* context) {
  43. threadContext = context;
  44. }
  45. namespace random {
  46. Xoroshiro128Plus& local() {
  47. static Xoroshiro128Plus rng;
  48. return rng;
  49. }
  50. } // namespace random
  51. }
  52. struct PluginLv2 {
  53. Context context;
  54. engine::Module* module;
  55. int frameCount = 0;
  56. int numInputs, numOutputs, numParams, numLights;
  57. void** ports;
  58. PluginLv2(double sr)
  59. {
  60. rack::random::Xoroshiro128Plus& rng(rack::random::local());
  61. if (! rng.isSeeded())
  62. {
  63. struct timeval tv;
  64. gettimeofday(&tv, NULL);
  65. uint64_t usec = uint64_t(tv.tv_sec) * 1000 * 1000 + tv.tv_usec;
  66. static uint64_t globalCounter = 1;
  67. rng.seed(usec, globalCounter++);
  68. for (int i = 0; i < 4; i++)
  69. rng();
  70. }
  71. context._engine.sampleRate = sr;
  72. contextSet(&context);
  73. module = PLUGIN_MODEL->createModule();
  74. numInputs = module->getNumInputs();
  75. numOutputs = module->getNumOutputs();
  76. numParams = module->getNumParams();
  77. numLights = module->getNumLights();
  78. ports = new void*[numInputs+numOutputs+numParams+numLights];
  79. Module::SampleRateChangeEvent e = { context._engine.sampleRate, 1.0f / context._engine.sampleRate };
  80. module->onSampleRateChange(e);
  81. // FIXME for CV ports we need to detect if something is connected
  82. for (int i=numInputs; --i >=0;)
  83. {
  84. if (!kCvInputs[i])
  85. module->inputs[i].channels = 1;
  86. }
  87. for (int i=numOutputs; --i >=0;)
  88. {
  89. if (!kCvOutputs[i])
  90. module->outputs[i].channels = 1;
  91. }
  92. d_stdout("Loaded " SLUG " :: %i inputs, %i outputs, %i params and %i lights",
  93. numInputs, numOutputs, numParams, numLights);
  94. }
  95. PluginLv2()
  96. {
  97. contextSet(&context);
  98. delete[] ports;
  99. delete module;
  100. }
  101. void lv2_connect_port(const uint32_t port, void* const dataLocation)
  102. {
  103. ports[port] = dataLocation;
  104. }
  105. void lv2_activate()
  106. {
  107. contextSet(&context);
  108. module->onReset();
  109. }
  110. void lv2_run(const uint32_t sampleCount)
  111. {
  112. if (sampleCount == 0)
  113. return;
  114. contextSet(&context);
  115. Module::ProcessArgs args = { context._engine.sampleRate, 1.0f / context._engine.sampleRate, frameCount };
  116. for (int i=numParams; --i >=0;)
  117. module->params[i].setValue(*static_cast<const float*>(ports[numInputs+numOutputs+i]));
  118. for (uint32_t s=0; s<sampleCount; ++s)
  119. {
  120. for (int i=numInputs; --i >=0;)
  121. {
  122. if (kCvInputs[i])
  123. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s]);
  124. else
  125. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s] * 10.0f);
  126. }
  127. module->doProcess(args);
  128. for (int i=numOutputs; --i >=0;)
  129. {
  130. if (kCvOutputs[i])
  131. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage();
  132. else
  133. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage() * 0.1f;
  134. }
  135. ++args.frame;
  136. }
  137. frameCount += sampleCount;
  138. }
  139. };
  140. static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  141. {
  142. return new PluginLv2(sampleRate);
  143. }
  144. // -----------------------------------------------------------------------
  145. #define instancePtr ((PluginLv2*)instance)
  146. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  147. {
  148. instancePtr->lv2_connect_port(port, dataLocation);
  149. }
  150. static void lv2_activate(LV2_Handle instance)
  151. {
  152. instancePtr->lv2_activate();
  153. }
  154. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  155. {
  156. instancePtr->lv2_run(sampleCount);
  157. }
  158. static void lv2_cleanup(LV2_Handle instance)
  159. {
  160. delete instancePtr;
  161. }
  162. // -----------------------------------------------------------------------
  163. static const void* lv2_extension_data(const char* uri)
  164. {
  165. return nullptr;
  166. }
  167. #undef instancePtr
  168. // -----------------------------------------------------------------------
  169. static const LV2_Descriptor sLv2Descriptor = {
  170. "urn:cardinal:" SLUG,
  171. lv2_instantiate,
  172. lv2_connect_port,
  173. lv2_activate,
  174. lv2_run,
  175. NULL, // deactivate
  176. lv2_cleanup,
  177. lv2_extension_data
  178. };
  179. DISTRHO_PLUGIN_EXPORT
  180. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  181. {
  182. USE_NAMESPACE_DISTRHO
  183. return (index == 0) ? &sLv2Descriptor : nullptr;
  184. }
  185. // -----------------------------------------------------------------------