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.

235 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. enum PortType {
  27. Audio = 0,
  28. Bi = 1,
  29. Uni = 2,
  30. };
  31. static constexpr const int kCvInputs[] = PLUGIN_CV_INPUTS;
  32. static constexpr const int kCvOutputs[] = PLUGIN_CV_OUTPUTS;
  33. #include "src/lv2/buf-size.h"
  34. #include "src/lv2/options.h"
  35. #include "DistrhoUtils.hpp"
  36. #include <time.h>
  37. #include <sys/time.h>
  38. namespace rack {
  39. static thread_local Context* threadContext = nullptr;
  40. Context* contextGet() {
  41. DISTRHO_SAFE_ASSERT(threadContext != nullptr);
  42. return threadContext;
  43. }
  44. #ifdef ARCH_MAC
  45. __attribute__((optnone))
  46. #endif
  47. void contextSet(Context* context) {
  48. threadContext = context;
  49. }
  50. namespace random {
  51. Xoroshiro128Plus& local() {
  52. static Xoroshiro128Plus rng;
  53. return rng;
  54. }
  55. } // namespace random
  56. }
  57. struct PluginLv2 {
  58. Context context;
  59. engine::Module* module;
  60. int frameCount = 0;
  61. int numInputs, numOutputs, numParams, numLights;
  62. void** ports;
  63. PluginLv2(double sr)
  64. {
  65. rack::random::Xoroshiro128Plus& rng(rack::random::local());
  66. if (! rng.isSeeded())
  67. {
  68. struct timeval tv;
  69. gettimeofday(&tv, NULL);
  70. uint64_t usec = uint64_t(tv.tv_sec) * 1000 * 1000 + tv.tv_usec;
  71. static uint64_t globalCounter = 1;
  72. rng.seed(usec, globalCounter++);
  73. for (int i = 0; i < 4; i++)
  74. rng();
  75. }
  76. context._engine.sampleRate = sr;
  77. contextSet(&context);
  78. module = PLUGIN_MODEL->createModule();
  79. numInputs = module->getNumInputs();
  80. numOutputs = module->getNumOutputs();
  81. numParams = module->getNumParams();
  82. numLights = module->getNumLights();
  83. ports = new void*[numInputs+numOutputs+numParams+numLights];
  84. Module::SampleRateChangeEvent e = { context._engine.sampleRate, 1.0f / context._engine.sampleRate };
  85. module->onSampleRateChange(e);
  86. // FIXME for CV ports we need to detect if something is connected
  87. for (int i=numInputs; --i >=0;)
  88. {
  89. // if (!kCvInputs[i])
  90. module->inputs[i].channels = 1;
  91. }
  92. for (int i=numOutputs; --i >=0;)
  93. {
  94. // if (!kCvOutputs[i])
  95. module->outputs[i].channels = 1;
  96. }
  97. d_stdout("Loaded " SLUG " :: %i inputs, %i outputs, %i params and %i lights",
  98. numInputs, numOutputs, numParams, numLights);
  99. }
  100. PluginLv2()
  101. {
  102. contextSet(&context);
  103. delete[] ports;
  104. delete module;
  105. }
  106. void lv2_connect_port(const uint32_t port, void* const dataLocation)
  107. {
  108. ports[port] = dataLocation;
  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. for (int i=numLights; --i >=0;)
  138. *static_cast<float*>(ports[numInputs+numOutputs+numParams+i]) = module->lights[i].getBrightness();
  139. frameCount += sampleCount;
  140. }
  141. };
  142. static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  143. {
  144. return new PluginLv2(sampleRate);
  145. }
  146. // -----------------------------------------------------------------------
  147. #define instancePtr ((PluginLv2*)instance)
  148. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  149. {
  150. instancePtr->lv2_connect_port(port, dataLocation);
  151. }
  152. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  153. {
  154. instancePtr->lv2_run(sampleCount);
  155. }
  156. static void lv2_cleanup(LV2_Handle instance)
  157. {
  158. delete instancePtr;
  159. }
  160. // -----------------------------------------------------------------------
  161. static const void* lv2_extension_data(const char* uri)
  162. {
  163. return nullptr;
  164. }
  165. #undef instancePtr
  166. // -----------------------------------------------------------------------
  167. static const LV2_Descriptor sLv2Descriptor = {
  168. "urn:cardinal:" SLUG,
  169. lv2_instantiate,
  170. lv2_connect_port,
  171. NULL, // activate
  172. lv2_run,
  173. NULL, // deactivate
  174. lv2_cleanup,
  175. lv2_extension_data
  176. };
  177. DISTRHO_PLUGIN_EXPORT
  178. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  179. {
  180. USE_NAMESPACE_DISTRHO
  181. return (index == 0) ? &sLv2Descriptor : nullptr;
  182. }
  183. // -----------------------------------------------------------------------