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.

212 lines
5.7KB

  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. #include "lv2plugin.hpp"
  18. #include "src/lv2/buf-size.h"
  19. #include "src/lv2/options.h"
  20. #include "DistrhoUtils.hpp"
  21. #include <time.h>
  22. #include <sys/time.h>
  23. namespace rack {
  24. static thread_local Context* threadContext = nullptr;
  25. Context* contextGet() {
  26. DISTRHO_SAFE_ASSERT(threadContext != nullptr);
  27. return threadContext;
  28. }
  29. #ifdef ARCH_MAC
  30. __attribute__((optnone))
  31. #endif
  32. void contextSet(Context* context) {
  33. threadContext = context;
  34. }
  35. namespace random {
  36. Xoroshiro128Plus& local() {
  37. static Xoroshiro128Plus rng;
  38. return rng;
  39. }
  40. } // namespace random
  41. }
  42. struct PluginLv2 {
  43. Context context;
  44. engine::Module* module;
  45. int frameCount = 0;
  46. int numInputs, numOutputs, numParams, numLights;
  47. void** ports;
  48. PluginLv2(double sr)
  49. {
  50. rack::random::Xoroshiro128Plus& rng(rack::random::local());
  51. if (! rng.isSeeded())
  52. {
  53. struct timeval tv;
  54. gettimeofday(&tv, NULL);
  55. uint64_t usec = uint64_t(tv.tv_sec) * 1000 * 1000 + tv.tv_usec;
  56. static uint64_t globalCounter = 1;
  57. rng.seed(usec, globalCounter++);
  58. for (int i = 0; i < 4; i++)
  59. rng();
  60. }
  61. context._engine.sampleRate = sr;
  62. contextSet(&context);
  63. module = PLUGIN_MODEL->createModule();
  64. numInputs = module->getNumInputs();
  65. numOutputs = module->getNumOutputs();
  66. numParams = module->getNumParams();
  67. numLights = module->getNumLights();
  68. ports = new void*[numInputs+numOutputs+numParams+numLights];
  69. Module::SampleRateChangeEvent e = { context._engine.sampleRate, 1.0f / context._engine.sampleRate };
  70. module->onSampleRateChange(e);
  71. // FIXME for CV ports we need to detect if something is connected
  72. for (int i=numInputs; --i >=0;)
  73. {
  74. // if (!kCvInputs[i])
  75. module->inputs[i].channels = 1;
  76. }
  77. for (int i=numOutputs; --i >=0;)
  78. {
  79. // if (!kCvOutputs[i])
  80. module->outputs[i].channels = 1;
  81. }
  82. d_stdout("Loaded " SLUG " :: %i inputs, %i outputs, %i params and %i lights",
  83. numInputs, numOutputs, numParams, numLights);
  84. }
  85. PluginLv2()
  86. {
  87. contextSet(&context);
  88. delete[] ports;
  89. delete module;
  90. }
  91. void lv2_connect_port(const uint32_t port, void* const dataLocation)
  92. {
  93. ports[port] = dataLocation;
  94. }
  95. void lv2_run(const uint32_t sampleCount)
  96. {
  97. if (sampleCount == 0)
  98. return;
  99. contextSet(&context);
  100. Module::ProcessArgs args = { context._engine.sampleRate, 1.0f / context._engine.sampleRate, frameCount };
  101. for (int i=numParams; --i >=0;)
  102. module->params[i].setValue(*static_cast<const float*>(ports[numInputs+numOutputs+i]));
  103. for (uint32_t s=0; s<sampleCount; ++s)
  104. {
  105. for (int i=numInputs; --i >=0;)
  106. {
  107. if (kCvInputs[i])
  108. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s]);
  109. else
  110. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s] * 10.0f);
  111. }
  112. module->doProcess(args);
  113. for (int i=numOutputs; --i >=0;)
  114. {
  115. if (kCvOutputs[i])
  116. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage();
  117. else
  118. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage() * 0.1f;
  119. }
  120. ++args.frame;
  121. }
  122. for (int i=numLights; --i >=0;)
  123. *static_cast<float*>(ports[numInputs+numOutputs+numParams+i]) = module->lights[i].getBrightness();
  124. frameCount += sampleCount;
  125. }
  126. };
  127. static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  128. {
  129. return new PluginLv2(sampleRate);
  130. }
  131. // -----------------------------------------------------------------------
  132. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  133. {
  134. static_cast<PluginLv2*>(instance)->lv2_connect_port(port, dataLocation);
  135. }
  136. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  137. {
  138. static_cast<PluginLv2*>(instance)->lv2_run(sampleCount);
  139. }
  140. static void lv2_cleanup(LV2_Handle instance)
  141. {
  142. delete static_cast<PluginLv2*>(instance);
  143. }
  144. // -----------------------------------------------------------------------
  145. static const void* lv2_extension_data(const char* uri)
  146. {
  147. return nullptr;
  148. }
  149. // -----------------------------------------------------------------------
  150. static const LV2_Descriptor sLv2Descriptor = {
  151. "urn:cardinal:" SLUG,
  152. lv2_instantiate,
  153. lv2_connect_port,
  154. NULL, // activate
  155. lv2_run,
  156. NULL, // deactivate
  157. lv2_cleanup,
  158. lv2_extension_data
  159. };
  160. DISTRHO_PLUGIN_EXPORT
  161. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  162. {
  163. USE_NAMESPACE_DISTRHO
  164. return (index == 0) ? &sLv2Descriptor : nullptr;
  165. }
  166. // -----------------------------------------------------------------------