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.

542 lines
15KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "DistrhoPluginInternal.hpp"
  17. #if DISTRHO_PLUGIN_HAS_UI
  18. # include "DistrhoUIInternal.hpp"
  19. #endif
  20. #include "CarlaNative.hpp"
  21. // -----------------------------------------------------------------------
  22. START_NAMESPACE_DISTRHO
  23. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  24. static const writeMidiFunc writeMidiCallback = nullptr;
  25. #endif
  26. #if DISTRHO_PLUGIN_HAS_UI
  27. // -----------------------------------------------------------------------
  28. // Carla UI
  29. #if ! DISTRHO_PLUGIN_WANT_STATE
  30. static const setStateFunc setStateCallback = nullptr;
  31. #endif
  32. #if ! DISTRHO_PLUGIN_IS_SYNTH
  33. static const sendNoteFunc sendNoteCallback = nullptr;
  34. #endif
  35. class UICarla
  36. {
  37. public:
  38. UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin)
  39. : fHost(host),
  40. fUI(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, plugin->getInstancePointer())
  41. {
  42. fUI.setWindowTitle(host->uiName);
  43. if (host->uiParentId != 0)
  44. fUI.setWindowTransientWinId(host->uiParentId);
  45. }
  46. ~UICarla()
  47. {
  48. fUI.quit();
  49. }
  50. // ---------------------------------------------
  51. void carla_show(const bool yesNo)
  52. {
  53. fUI.setWindowVisible(yesNo);
  54. }
  55. bool carla_idle()
  56. {
  57. return fUI.idle();
  58. }
  59. void carla_setParameterValue(const uint32_t index, const float value)
  60. {
  61. fUI.parameterChanged(index, value);
  62. }
  63. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  64. void carla_setMidiProgram(const uint32_t realProgram)
  65. {
  66. fUI.programLoaded(realProgram);
  67. }
  68. #endif
  69. #if DISTRHO_PLUGIN_WANT_STATE
  70. void carla_setCustomData(const char* const key, const char* const value)
  71. {
  72. fUI.stateChanged(key, value);
  73. }
  74. #endif
  75. void carla_setUiTitle(const char* const uiTitle)
  76. {
  77. fUI.setWindowTitle(uiTitle);
  78. }
  79. // ---------------------------------------------
  80. protected:
  81. void handleEditParameter(const uint32_t rindex, const bool touch)
  82. {
  83. fHost->dispatcher(fHost->handle,
  84. NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER,
  85. static_cast<int32_t>(rindex),
  86. touch ? 1 : 0,
  87. nullptr, 0.0f);
  88. }
  89. void handleSetParameterValue(const uint32_t rindex, const float value)
  90. {
  91. fHost->ui_parameter_changed(fHost->handle, rindex, value);
  92. }
  93. #if DISTRHO_PLUGIN_WANT_STATE
  94. void handleSetState(const char* const key, const char* const value)
  95. {
  96. fHost->ui_custom_data_changed(fHost->handle, key, value);
  97. }
  98. #endif
  99. #if DISTRHO_PLUGIN_IS_SYNTH
  100. void handleSendNote(const uint8_t, const uint8_t, const uint8_t)
  101. {
  102. // TODO
  103. }
  104. #endif
  105. void handleSetSize(const uint width, const uint height)
  106. {
  107. fUI.setWindowSize(width, height);
  108. }
  109. // ---------------------------------------------
  110. private:
  111. // Plugin stuff
  112. const NativeHostDescriptor* const fHost;
  113. // UI
  114. UIExporter fUI;
  115. // ---------------------------------------------
  116. // Callbacks
  117. #define handlePtr ((UICarla*)ptr)
  118. static void editParameterCallback(void* ptr, uint32_t index, bool started)
  119. {
  120. handlePtr->handleEditParameter(index, started);
  121. }
  122. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  123. {
  124. handlePtr->handleSetParameterValue(rindex, value);
  125. }
  126. #if DISTRHO_PLUGIN_WANT_STATE
  127. static void setStateCallback(void* ptr, const char* key, const char* value)
  128. {
  129. handlePtr->handleSetState(key, value);
  130. }
  131. #endif
  132. #if DISTRHO_PLUGIN_IS_SYNTH
  133. static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
  134. {
  135. handlePtr->handleSendNote(channel, note, velocity);
  136. }
  137. #endif
  138. static void setSizeCallback(void* ptr, uint width, uint height)
  139. {
  140. handlePtr->handleSetSize(width, height);
  141. }
  142. #undef handlePtr
  143. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla)
  144. };
  145. #endif // DISTRHO_PLUGIN_HAS_UI
  146. // -----------------------------------------------------------------------
  147. // Carla Plugin
  148. class PluginCarla : public NativePluginClass
  149. {
  150. public:
  151. PluginCarla(const NativeHostDescriptor* const host)
  152. : NativePluginClass(host),
  153. fPlugin(this, writeMidiCallback),
  154. fScalePointsCache(nullptr)
  155. {
  156. #if DISTRHO_PLUGIN_HAS_UI
  157. fUiPtr = nullptr;
  158. #endif
  159. }
  160. ~PluginCarla() override
  161. {
  162. #if DISTRHO_PLUGIN_HAS_UI
  163. if (fUiPtr != nullptr)
  164. {
  165. delete fUiPtr;
  166. fUiPtr = nullptr;
  167. }
  168. #endif
  169. if (fScalePointsCache != nullptr)
  170. {
  171. delete[] fScalePointsCache;
  172. fScalePointsCache = nullptr;
  173. }
  174. }
  175. protected:
  176. // -------------------------------------------------------------------
  177. // Plugin parameter calls
  178. uint32_t getParameterCount() const override
  179. {
  180. return fPlugin.getParameterCount();
  181. }
  182. const NativeParameter* getParameterInfo(const uint32_t index) const override
  183. {
  184. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), nullptr);
  185. static NativeParameter param;
  186. param.scalePointCount = 0;
  187. param.scalePoints = nullptr;
  188. {
  189. int nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED;
  190. const uint32_t paramHints = fPlugin.getParameterHints(index);
  191. if (paramHints & kParameterIsAutomable)
  192. nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE;
  193. if (paramHints & kParameterIsBoolean)
  194. nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN;
  195. if (paramHints & kParameterIsInteger)
  196. nativeParamHints |= ::NATIVE_PARAMETER_IS_INTEGER;
  197. if (paramHints & kParameterIsLogarithmic)
  198. nativeParamHints |= ::NATIVE_PARAMETER_IS_LOGARITHMIC;
  199. if (paramHints & kParameterIsOutput)
  200. nativeParamHints |= ::NATIVE_PARAMETER_IS_OUTPUT;
  201. param.hints = static_cast<NativeParameterHints>(nativeParamHints);
  202. }
  203. param.name = fPlugin.getParameterName(index);
  204. param.unit = fPlugin.getParameterUnit(index);
  205. {
  206. const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
  207. param.ranges.def = ranges.def;
  208. param.ranges.min = ranges.min;
  209. param.ranges.max = ranges.max;
  210. }
  211. {
  212. const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index));
  213. if (const uint32_t scalePointCount = enumValues.count)
  214. {
  215. NativeParameterScalePoint* const scalePoints = new NativeParameterScalePoint[scalePointCount];
  216. for (uint32_t i=0; i<scalePointCount; ++i)
  217. {
  218. scalePoints[i].label = enumValues.values[i].label.buffer();
  219. scalePoints[i].value = enumValues.values[i].value;
  220. }
  221. param.scalePoints = scalePoints;
  222. param.scalePointCount = scalePointCount;
  223. if (enumValues.restrictedMode)
  224. param.hints = static_cast<NativeParameterHints>(param.hints|::NATIVE_PARAMETER_USES_SCALEPOINTS);
  225. }
  226. else if (fScalePointsCache != nullptr)
  227. {
  228. delete[] fScalePointsCache;
  229. fScalePointsCache = nullptr;
  230. }
  231. }
  232. return &param;
  233. }
  234. float getParameterValue(const uint32_t index) const override
  235. {
  236. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), 0.0f);
  237. return fPlugin.getParameterValue(index);
  238. }
  239. // -------------------------------------------------------------------
  240. // Plugin midi-program calls
  241. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  242. uint32_t getMidiProgramCount() const override
  243. {
  244. return fPlugin.getProgramCount();
  245. }
  246. const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override
  247. {
  248. CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(), nullptr);
  249. static NativeMidiProgram midiProgram;
  250. midiProgram.bank = index / 128;
  251. midiProgram.program = index % 128;
  252. midiProgram.name = fPlugin.getProgramName(index);
  253. return &midiProgram;
  254. }
  255. #endif
  256. // -------------------------------------------------------------------
  257. // Plugin state calls
  258. void setParameterValue(const uint32_t index, const float value) override
  259. {
  260. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  261. fPlugin.setParameterValue(index, value);
  262. }
  263. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  264. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  265. {
  266. const uint32_t realProgram(bank * 128 + program);
  267. CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),);
  268. fPlugin.loadProgram(realProgram);
  269. }
  270. #endif
  271. #if DISTRHO_PLUGIN_WANT_STATE
  272. void setCustomData(const char* const key, const char* const value) override
  273. {
  274. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  275. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  276. fPlugin.setState(key, value);
  277. }
  278. #endif
  279. // -------------------------------------------------------------------
  280. // Plugin process calls
  281. void activate() override
  282. {
  283. fPlugin.activate();
  284. }
  285. void deactivate() override
  286. {
  287. fPlugin.deactivate();
  288. }
  289. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  290. void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames,
  291. const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  292. {
  293. MidiEvent realMidiEvents[midiEventCount];
  294. for (uint32_t i=0; i < midiEventCount; ++i)
  295. {
  296. const NativeMidiEvent& midiEvent(midiEvents[i]);
  297. MidiEvent& realMidiEvent(realMidiEvents[i]);
  298. realMidiEvent.frame = midiEvent.time;
  299. realMidiEvent.size = midiEvent.size;
  300. uint8_t j=0;
  301. for (; j<midiEvent.size; ++j)
  302. realMidiEvent.data[j] = midiEvent.data[j];
  303. for (; j<midiEvent.size; ++j)
  304. realMidiEvent.data[j] = midiEvent.data[j];
  305. realMidiEvent.dataExt = nullptr;
  306. }
  307. fPlugin.run(inBuffer, outBuffer, frames, realMidiEvents, midiEventCount);
  308. }
  309. #else
  310. void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames,
  311. const NativeMidiEvent* const, const uint32_t) override
  312. {
  313. fPlugin.run(inBuffer, outBuffer, frames);
  314. }
  315. #endif
  316. // -------------------------------------------------------------------
  317. // Plugin UI calls
  318. #if DISTRHO_PLUGIN_HAS_UI
  319. void uiShow(const bool show) override
  320. {
  321. if (show)
  322. {
  323. createUiIfNeeded();
  324. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  325. fUiPtr->carla_show(show);
  326. }
  327. else if (fUiPtr != nullptr)
  328. {
  329. delete fUiPtr;
  330. fUiPtr = nullptr;
  331. }
  332. }
  333. void uiIdle() override
  334. {
  335. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  336. if (! fUiPtr->carla_idle())
  337. {
  338. uiClosed();
  339. delete fUiPtr;
  340. fUiPtr = nullptr;
  341. }
  342. }
  343. void uiSetParameterValue(const uint32_t index, const float value) override
  344. {
  345. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  346. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  347. fUiPtr->carla_setParameterValue(index, value);
  348. }
  349. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  350. void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  351. {
  352. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  353. const uint32_t realProgram(bank * 128 + program);
  354. CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),);
  355. fUiPtr->carla_setMidiProgram(realProgram);
  356. }
  357. # endif
  358. # if DISTRHO_PLUGIN_WANT_STATE
  359. void uiSetCustomData(const char* const key, const char* const value) override
  360. {
  361. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  362. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  363. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  364. fUiPtr->carla_setCustomData(key, value);
  365. }
  366. # endif
  367. #endif
  368. // -------------------------------------------------------------------
  369. // Plugin dispatcher calls
  370. void bufferSizeChanged(const uint32_t bufferSize) override
  371. {
  372. fPlugin.setBufferSize(bufferSize, true);
  373. }
  374. void sampleRateChanged(const double sampleRate) override
  375. {
  376. fPlugin.setSampleRate(sampleRate, true);
  377. }
  378. #if DISTRHO_PLUGIN_HAS_UI
  379. void uiNameChanged(const char* const uiName) override
  380. {
  381. CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,);
  382. fUiPtr->carla_setUiTitle(uiName);
  383. }
  384. #endif
  385. // -------------------------------------------------------------------
  386. private:
  387. PluginExporter fPlugin;
  388. mutable NativeParameterScalePoint* fScalePointsCache;
  389. #if DISTRHO_PLUGIN_HAS_UI
  390. // UI
  391. UICarla* fUiPtr;
  392. void createUiIfNeeded()
  393. {
  394. if (fUiPtr == nullptr)
  395. {
  396. d_lastUiSampleRate = getSampleRate();
  397. fUiPtr = new UICarla(getHostHandle(), &fPlugin);
  398. }
  399. }
  400. #endif
  401. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  402. static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
  403. {
  404. if (midiEvent.size > 4)
  405. return;
  406. const NativeMidiEvent event = {
  407. midiEvent.frame, 0, midiEvent.size, midiEvent.data
  408. };
  409. return ((PluginCarla*)ptr)->fPlugin.writeMidiEvent(midiEvent);
  410. }
  411. #endif
  412. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla)
  413. // -------------------------------------------------------------------
  414. public:
  415. static NativePluginHandle _instantiate(const NativeHostDescriptor* host)
  416. {
  417. d_lastBufferSize = host->get_buffer_size(host->handle);
  418. d_lastSampleRate = host->get_sample_rate(host->handle);
  419. return new PluginCarla(host);
  420. }
  421. static void _cleanup(NativePluginHandle handle)
  422. {
  423. delete (PluginCarla*)handle;
  424. }
  425. };
  426. END_NAMESPACE_DISTRHO
  427. // -----------------------------------------------------------------------