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.

210 lines
5.4KB

  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. namespace rack {
  32. static thread_local Context* threadContext = nullptr;
  33. Context* contextGet() {
  34. DISTRHO_SAFE_ASSERT(threadContext != nullptr);
  35. return threadContext;
  36. }
  37. #ifdef ARCH_MAC
  38. __attribute__((optnone))
  39. #endif
  40. void contextSet(Context* context) {
  41. threadContext = context;
  42. }
  43. }
  44. struct PluginLv2 {
  45. Context context;
  46. engine::Module* module;
  47. int frameCount = 0;
  48. int numInputs, numOutputs, numParams, numLights;
  49. void** ports;
  50. PluginLv2(double sr)
  51. {
  52. context._engine.sampleRate = sr;
  53. contextSet(&context);
  54. module = PLUGIN_MODEL->createModule();
  55. numInputs = module->getNumInputs();
  56. numOutputs = module->getNumOutputs();
  57. numParams = module->getNumParams();
  58. numLights = module->getNumLights();
  59. ports = new void*[numInputs+numOutputs+numParams+numLights];
  60. Module::SampleRateChangeEvent e = { context._engine.sampleRate, 1.0f / context._engine.sampleRate };
  61. module->onSampleRateChange(e);
  62. // FIXME for CV ports we need to detect if something is connected
  63. for (int i=numInputs; --i >=0;)
  64. {
  65. if (!kCvInputs[i])
  66. module->inputs[i].channels = 1;
  67. }
  68. for (int i=numOutputs; --i >=0;)
  69. {
  70. if (!kCvOutputs[i])
  71. module->outputs[i].channels = 1;
  72. }
  73. d_stdout("Loaded " SLUG " :: %i inputs, %i outputs, %i params and %i lights",
  74. numInputs, numOutputs, numParams, numLights);
  75. }
  76. PluginLv2()
  77. {
  78. contextSet(&context);
  79. delete[] ports;
  80. delete module;
  81. }
  82. void lv2_connect_port(const uint32_t port, void* const dataLocation)
  83. {
  84. ports[port] = dataLocation;
  85. }
  86. void lv2_activate()
  87. {
  88. contextSet(&context);
  89. module->onReset();
  90. }
  91. void lv2_run(const uint32_t sampleCount)
  92. {
  93. if (sampleCount == 0)
  94. return;
  95. contextSet(&context);
  96. Module::ProcessArgs args = { context._engine.sampleRate, 1.0f / context._engine.sampleRate, frameCount };
  97. for (int i=numParams; --i >=0;)
  98. module->params[i].setValue(*static_cast<const float*>(ports[numInputs+numOutputs+i]));
  99. for (uint32_t s=0; s<sampleCount; ++s)
  100. {
  101. for (int i=numInputs; --i >=0;)
  102. {
  103. if (kCvInputs[i])
  104. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s]);
  105. else
  106. module->inputs[i].setVoltage(static_cast<const float*>(ports[i])[s] * 10.0f);
  107. }
  108. module->doProcess(args);
  109. for (int i=numOutputs; --i >=0;)
  110. {
  111. if (kCvOutputs[i])
  112. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage();
  113. else
  114. static_cast<float*>(ports[numInputs+i])[s] = module->outputs[i].getVoltage() * 0.1f;
  115. }
  116. ++args.frame;
  117. }
  118. frameCount += sampleCount;
  119. }
  120. };
  121. static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  122. {
  123. return new PluginLv2(sampleRate);
  124. }
  125. // -----------------------------------------------------------------------
  126. #define instancePtr ((PluginLv2*)instance)
  127. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  128. {
  129. instancePtr->lv2_connect_port(port, dataLocation);
  130. }
  131. static void lv2_activate(LV2_Handle instance)
  132. {
  133. instancePtr->lv2_activate();
  134. }
  135. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  136. {
  137. instancePtr->lv2_run(sampleCount);
  138. }
  139. static void lv2_cleanup(LV2_Handle instance)
  140. {
  141. delete instancePtr;
  142. }
  143. // -----------------------------------------------------------------------
  144. static const void* lv2_extension_data(const char* uri)
  145. {
  146. return nullptr;
  147. }
  148. #undef instancePtr
  149. // -----------------------------------------------------------------------
  150. static const LV2_Descriptor sLv2Descriptor = {
  151. "urn:cardinal:" SLUG,
  152. lv2_instantiate,
  153. lv2_connect_port,
  154. lv2_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. // -----------------------------------------------------------------------