Audio plugin host https://kx.studio/carla
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.

400 lines
12KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2015 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 2 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 doc/GPL.txt file.
  16. */
  17. #include "CarlaNative.hpp"
  18. #include "CarlaMutex.hpp"
  19. #include "CarlaJuceUtils.hpp"
  20. #include "juce_audio_basics.h"
  21. #include "zita-bls1/source/png2img.cc"
  22. #include "zita-bls1/source/guiclass.cc"
  23. #include "zita-bls1/source/hp3filt.cc"
  24. #include "zita-bls1/source/jclient.cc"
  25. #include "zita-bls1/source/lfshelf2.cc"
  26. #include "zita-bls1/source/mainwin.cc"
  27. #include "zita-bls1/source/rotary.cc"
  28. #include "zita-bls1/source/shuffler.cc"
  29. #include "zita-bls1/source/styles.cc"
  30. using juce::FloatVectorOperations;
  31. using juce::ScopedPointer;
  32. // -----------------------------------------------------------------------
  33. // BLS1 Plugin
  34. class BLS1Plugin : public NativePluginClass
  35. {
  36. public:
  37. static const uint32_t kNumInputs = 2;
  38. static const uint32_t kNumOutputs = 2;
  39. enum Parameters {
  40. kParameterINPBAL,
  41. kParameterHPFILT,
  42. kParameterSHGAIN,
  43. kParameterSHFREQ,
  44. kParameterLFFREQ,
  45. kParameterLFGAIN,
  46. kParameterNROTARY
  47. };
  48. BLS1Plugin(const NativeHostDescriptor* const host)
  49. : NativePluginClass(host),
  50. fJackClient(),
  51. xresman(),
  52. jclient(nullptr),
  53. display(nullptr),
  54. rootwin(nullptr),
  55. mainwin(nullptr),
  56. handler(nullptr),
  57. leakDetector_BLS1Plugin()
  58. {
  59. CARLA_SAFE_ASSERT(host != nullptr);
  60. carla_zeroStruct(fJackClient);
  61. gLastJackClient = &fJackClient;
  62. fJackClient.clientName = "bls1";
  63. fJackClient.bufferSize = getBufferSize();
  64. fJackClient.sampleRate = getSampleRate();
  65. int argc = 1;
  66. char* argv[] = { (char*)"bls1" };
  67. xresman.init(&argc, argv, (char*)"bls1", nullptr, 0);
  68. jclient = new Jclient(xresman.rname(), nullptr);
  69. // set initial values
  70. fParameters[kParameterINPBAL] = 0.0f;
  71. fParameters[kParameterHPFILT] = 40.0f;
  72. fParameters[kParameterSHGAIN] = 15.0f;
  73. fParameters[kParameterSHFREQ] = 5e2f;
  74. fParameters[kParameterLFFREQ] = 80.0f;
  75. fParameters[kParameterLFGAIN] = 0.0f;
  76. jclient->set_inpbal(fParameters[kParameterINPBAL]);
  77. jclient->set_hpfilt(fParameters[kParameterHPFILT]);
  78. jclient->shuffler()->prepare(fParameters[kParameterSHGAIN], fParameters[kParameterSHFREQ]);
  79. jclient->set_loshelf(fParameters[kParameterLFGAIN], fParameters[kParameterLFFREQ]);
  80. }
  81. // -------------------------------------------------------------------
  82. // Plugin parameter calls
  83. uint32_t getParameterCount() const override
  84. {
  85. return kParameterNROTARY;
  86. }
  87. const NativeParameter* getParameterInfo(const uint32_t index) const override
  88. {
  89. CARLA_SAFE_ASSERT_RETURN(index < kParameterNROTARY, nullptr);
  90. static NativeParameter param;
  91. int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE;
  92. // reset
  93. param.name = nullptr;
  94. param.unit = nullptr;
  95. param.ranges.def = 0.0f;
  96. param.ranges.min = 0.0f;
  97. param.ranges.max = 1.0f;
  98. param.ranges.step = 1.0f;
  99. param.ranges.stepSmall = 1.0f;
  100. param.ranges.stepLarge = 1.0f;
  101. param.scalePointCount = 0;
  102. param.scalePoints = nullptr;
  103. switch (index)
  104. {
  105. case kParameterINPBAL:
  106. param.name = "INPBAL";
  107. param.ranges.def = 0.0f;
  108. param.ranges.min = -3.0f;
  109. param.ranges.max = 3.0f;
  110. break;
  111. case kParameterHPFILT:
  112. hints |= NATIVE_PARAMETER_IS_LOGARITHMIC;
  113. param.name = "HPFILT";
  114. param.ranges.def = 40.0f;
  115. param.ranges.min = 10.0f;
  116. param.ranges.max = 320.0f;
  117. break;
  118. case kParameterSHGAIN:
  119. param.name = "SHGAIN";
  120. param.ranges.def = 15.0f;
  121. param.ranges.min = 0.0f;
  122. param.ranges.max = 24.0f;
  123. break;
  124. case kParameterSHFREQ:
  125. hints |= NATIVE_PARAMETER_IS_LOGARITHMIC;
  126. param.name = "SHFREQ";
  127. param.ranges.def = 5e2f;
  128. param.ranges.min = 125.0f;
  129. param.ranges.max = 2e3f;
  130. break;
  131. case kParameterLFFREQ:
  132. hints |= NATIVE_PARAMETER_IS_LOGARITHMIC;
  133. param.name = "LFFREQ";
  134. param.ranges.def = 80.0f;
  135. param.ranges.min = 20.0f;
  136. param.ranges.max = 320.0f;
  137. break;
  138. case kParameterLFGAIN:
  139. param.name = "LFGAIN";
  140. param.ranges.def = 0.0f;
  141. param.ranges.min = -9.0f;
  142. param.ranges.max = 9.0f;
  143. break;
  144. }
  145. param.hints = static_cast<NativeParameterHints>(hints);
  146. return &param;
  147. }
  148. float getParameterValue(const uint32_t index) const override
  149. {
  150. CARLA_SAFE_ASSERT_RETURN(index < kParameterNROTARY, 0.0f);
  151. return fParameters[index];
  152. }
  153. // -------------------------------------------------------------------
  154. // Plugin state calls
  155. void setParameterValue(const uint32_t index, const float value) override
  156. {
  157. CARLA_SAFE_ASSERT_RETURN(index < kParameterNROTARY,);
  158. fParameters[index] = value;
  159. switch (index)
  160. {
  161. case kParameterINPBAL:
  162. jclient->set_inpbal(value);
  163. break;
  164. case kParameterHPFILT:
  165. jclient->set_hpfilt(value);
  166. break;
  167. case kParameterSHGAIN:
  168. jclient->shuffler()->prepare(value, fParameters[kParameterSHFREQ]);
  169. break;
  170. case kParameterSHFREQ:
  171. jclient->shuffler()->prepare(fParameters[kParameterSHGAIN], value);
  172. break;
  173. case kParameterLFFREQ:
  174. jclient->set_loshelf(fParameters[kParameterLFGAIN], value);
  175. break;
  176. case kParameterLFGAIN:
  177. jclient->set_loshelf(value, fParameters[kParameterLFFREQ]);
  178. break;
  179. }
  180. }
  181. // -------------------------------------------------------------------
  182. // Plugin process calls
  183. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const, const uint32_t) override
  184. {
  185. if (! fJackClient.active)
  186. {
  187. const int iframes(static_cast<int>(frames));
  188. for (uint32_t i=0; i<kNumInputs; ++i)
  189. FloatVectorOperations::clear(outBuffer[i], iframes);
  190. return;
  191. }
  192. for (uint32_t i=0; i<kNumInputs; ++i)
  193. fJackClient.portsAudioIn[i]->buffer = inBuffer[i];
  194. for (uint32_t i=0; i<kNumOutputs; ++i)
  195. fJackClient.portsAudioOut[i]->buffer = outBuffer[i];
  196. fJackClient.processCallback(frames, fJackClient.processPtr);
  197. }
  198. // -------------------------------------------------------------------
  199. // Plugin UI calls
  200. void uiShow(const bool show) override
  201. {
  202. if (show)
  203. {
  204. if (display == nullptr)
  205. {
  206. display = new X_display(nullptr);
  207. if (display->dpy() == nullptr)
  208. return hostUiUnavailable();
  209. styles_init(display, &xresman);
  210. rootwin = new X_rootwin(display);
  211. mainwin = new Mainwin(rootwin, &xresman, 0, 0, jclient);
  212. rootwin->handle_event();
  213. mainwin->x_set_title(getUiName());
  214. handler = new X_handler(display, mainwin, EV_X11);
  215. if (const uintptr_t winId = getUiParentId())
  216. XSetTransientForHint(display->dpy(), mainwin->win(), static_cast<Window>(winId));
  217. }
  218. handler->next_event();
  219. XFlush(display->dpy());
  220. }
  221. else
  222. {
  223. handler = nullptr;
  224. mainwin = nullptr;
  225. rootwin = nullptr;
  226. display = nullptr;
  227. }
  228. }
  229. void uiIdle() override
  230. {
  231. if (mainwin == nullptr)
  232. return;
  233. int ev;
  234. for (; (ev = mainwin->process()) == EV_X11;)
  235. {
  236. rootwin->handle_event();
  237. handler->next_event();
  238. }
  239. // check if parameters were updated
  240. float value;
  241. for (uint32_t i=0; i<kParameterNROTARY; ++i)
  242. {
  243. value = mainwin->_rotary[i]->value();
  244. if (fParameters[i] == value)
  245. continue;
  246. fParameters[i] = value;
  247. uiParameterChanged(i, value);
  248. }
  249. if (ev == EV_EXIT)
  250. {
  251. handler = nullptr;
  252. mainwin = nullptr;
  253. rootwin = nullptr;
  254. display = nullptr;
  255. uiClosed();
  256. }
  257. }
  258. void uiSetParameterValue(const uint32_t index, const float value) override
  259. {
  260. CARLA_SAFE_ASSERT_RETURN(index < kParameterNROTARY,);
  261. if (mainwin == nullptr)
  262. return;
  263. mainwin->_rotary[index]->set_value(value);
  264. }
  265. // -------------------------------------------------------------------
  266. // Plugin dispatcher calls
  267. void bufferSizeChanged(const uint32_t bufferSize) override
  268. {
  269. fJackClient.bufferSize = bufferSize;
  270. }
  271. void sampleRateChanged(const double sampleRate) override
  272. {
  273. fJackClient.sampleRate = sampleRate;
  274. }
  275. void uiNameChanged(const char* const uiName) override
  276. {
  277. CARLA_SAFE_ASSERT_RETURN(uiName != nullptr && uiName[0] != '\0',);
  278. if (mainwin == nullptr)
  279. return;
  280. mainwin->x_set_title(uiName);
  281. }
  282. // -------------------------------------------------------------------
  283. private:
  284. // Fake jack client
  285. jack_client_t fJackClient;
  286. // Zita stuff (core)
  287. X_resman xresman;
  288. ScopedPointer<Jclient> jclient;
  289. ScopedPointer<X_display> display;
  290. ScopedPointer<X_rootwin> rootwin;
  291. ScopedPointer<Mainwin> mainwin;
  292. ScopedPointer<X_handler> handler;
  293. float fParameters[kParameterNROTARY];
  294. PluginClassEND(BLS1Plugin)
  295. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BLS1Plugin)
  296. };
  297. // -----------------------------------------------------------------------
  298. static const NativePluginDescriptor bls1Desc = {
  299. /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
  300. /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
  301. |NATIVE_PLUGIN_HAS_UI
  302. |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS
  303. |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD
  304. |NATIVE_PLUGIN_USES_PARENT_ID),
  305. /* supports */ static_cast<NativePluginSupports>(0x0),
  306. /* audioIns */ BLS1Plugin::kNumInputs,
  307. /* audioOuts */ BLS1Plugin::kNumOutputs,
  308. /* midiIns */ 0,
  309. /* midiOuts */ 0,
  310. /* paramIns */ BLS1Plugin::kParameterNROTARY,
  311. /* paramOuts */ 0,
  312. /* name */ "BLS1",
  313. /* label */ "bls1",
  314. /* maker */ "Fons Adriaensen",
  315. /* copyright */ "GPL v2+",
  316. PluginDescriptorFILL(BLS1Plugin)
  317. };
  318. // -----------------------------------------------------------------------
  319. CARLA_EXPORT
  320. void carla_register_native_plugin_zita_bls1();
  321. CARLA_EXPORT
  322. void carla_register_native_plugin_zita_bls1()
  323. {
  324. carla_register_native_plugin(&bls1Desc);
  325. }
  326. // -----------------------------------------------------------------------