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.

zita-bls1.cpp 12KB

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