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.

229 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_run(const uint32_t sampleCount)
  106. {
  107. if (sampleCount == 0)
  108. return;
  109. contextSet(&context);
  110. Module::ProcessArgs args = { context._engine.sampleRate, 1.0f / context._engine.sampleRate, frameCount };
  111. for (int i=numParams; --i >=0;)
  112. module->params[i].setValue(*static_cast<const float*>(ports[numInputs+numOutputs+i]));
  113. for (uint32_t s=0; s<sampleCount; ++s)
  114. {
  115. for (int i=numInputs; --i >=0;)
  116. {
  117. if (kCvInputs[i])
  118. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s]);
  119. else
  120. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s] * 10.0f);
  121. }
  122. module->doProcess(args);
  123. for (int i=numOutputs; --i >=0;)
  124. {
  125. if (kCvOutputs[i])
  126. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage();
  127. else
  128. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage() * 0.1f;
  129. }
  130. ++args.frame;
  131. }
  132. for (int i=numLights; --i >=0;)
  133. *static_cast<float*>(ports[numInputs+numOutputs+numParams+i]) = module->lights[i].getBrightness();
  134. frameCount += sampleCount;
  135. }
  136. };
  137. static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  138. {
  139. return new PluginLv2(sampleRate);
  140. }
  141. // -----------------------------------------------------------------------
  142. #define instancePtr ((PluginLv2*)instance)
  143. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  144. {
  145. instancePtr->lv2_connect_port(port, dataLocation);
  146. }
  147. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  148. {
  149. instancePtr->lv2_run(sampleCount);
  150. }
  151. static void lv2_cleanup(LV2_Handle instance)
  152. {
  153. delete instancePtr;
  154. }
  155. // -----------------------------------------------------------------------
  156. static const void* lv2_extension_data(const char* uri)
  157. {
  158. return nullptr;
  159. }
  160. #undef instancePtr
  161. // -----------------------------------------------------------------------
  162. static const LV2_Descriptor sLv2Descriptor = {
  163. "urn:cardinal:" SLUG,
  164. lv2_instantiate,
  165. lv2_connect_port,
  166. NULL, // activate
  167. lv2_run,
  168. NULL, // deactivate
  169. lv2_cleanup,
  170. lv2_extension_data
  171. };
  172. DISTRHO_PLUGIN_EXPORT
  173. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  174. {
  175. USE_NAMESPACE_DISTRHO
  176. return (index == 0) ? &sLv2Descriptor : nullptr;
  177. }
  178. // -----------------------------------------------------------------------