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.

xycontroller.cpp 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * XY Controller UI, taken from Cadence
  3. * Copyright (C) 2011-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 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 "CarlaDefines.h"
  18. #include "CarlaMIDI.h"
  19. #include "CarlaNativeExtUI.hpp"
  20. #include "midi-queue.hpp"
  21. #include "water/text/StringArray.h"
  22. // -----------------------------------------------------------------------
  23. class XYControllerPlugin : public NativePluginAndUiClass
  24. {
  25. public:
  26. enum Parameters {
  27. kParamInX,
  28. kParamInY,
  29. kParamOutX,
  30. kParamOutY,
  31. kParamCount,
  32. };
  33. XYControllerPlugin(const NativeHostDescriptor* const host)
  34. : NativePluginAndUiClass(host, "xycontroller-ui"),
  35. params(),
  36. channels(),
  37. mqueue(),
  38. mqueueRT()
  39. {
  40. carla_zeroStruct(params);
  41. carla_zeroStruct(channels);
  42. channels[0] = true;
  43. }
  44. protected:
  45. // -------------------------------------------------------------------
  46. // Plugin parameter calls
  47. uint32_t getParameterCount() const override
  48. {
  49. return kParamCount;
  50. }
  51. const NativeParameter* getParameterInfo(const uint32_t index) const override
  52. {
  53. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, nullptr);
  54. static NativeParameter param;
  55. int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMATABLE;
  56. param.name = nullptr;
  57. param.unit = "%";
  58. param.ranges.def = 0.0f;
  59. param.ranges.min = -100.0f;
  60. param.ranges.max = 100.0f;
  61. param.ranges.step = 1.0f;
  62. param.ranges.stepSmall = 0.01f;
  63. param.ranges.stepLarge = 10.0f;
  64. param.scalePointCount = 0;
  65. param.scalePoints = nullptr;
  66. switch (index)
  67. {
  68. case kParamInX:
  69. param.name = "X";
  70. break;
  71. case kParamInY:
  72. param.name = "Y";
  73. break;
  74. case kParamOutX:
  75. hints |= NATIVE_PARAMETER_IS_OUTPUT;
  76. param.name = "Out X";
  77. break;
  78. case kParamOutY:
  79. hints |= NATIVE_PARAMETER_IS_OUTPUT;
  80. param.name = "Out Y";
  81. break;
  82. }
  83. param.hints = static_cast<NativeParameterHints>(hints);
  84. return &param;
  85. }
  86. float getParameterValue(const uint32_t index) const override
  87. {
  88. CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f);
  89. return params[index];
  90. }
  91. // -------------------------------------------------------------------
  92. // Plugin state calls
  93. void setParameterValue(const uint32_t index, const float value) override
  94. {
  95. switch (index)
  96. {
  97. case kParamInX:
  98. case kParamInY:
  99. params[index] = value;
  100. break;
  101. }
  102. }
  103. void setCustomData(const char* const key, const char* const value) override
  104. {
  105. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  106. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  107. if (std::strcmp(key, "channels") == 0)
  108. {
  109. const water::StringArray chans(water::StringArray::fromTokens(value, ",", ""));
  110. carla_zeroStruct(channels);
  111. for (const water::String *it=chans.begin(), *end=chans.end(); it != end; ++it)
  112. {
  113. const int ichan = std::atoi((*it).toRawUTF8());
  114. CARLA_SAFE_ASSERT_INT_CONTINUE(ichan >= 1 && ichan <= 16, ichan);
  115. channels[ichan-1] = true;
  116. }
  117. }
  118. }
  119. // -------------------------------------------------------------------
  120. // Plugin process calls
  121. void process(const float* const*, float**, const uint32_t,
  122. const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  123. {
  124. params[kParamOutX] = params[kParamInX];
  125. params[kParamOutY] = params[kParamInY];
  126. if (mqueue.isNotEmpty() && mqueueRT.tryToCopyDataFrom(mqueue))
  127. {
  128. uint8_t d1, d2, d3;
  129. NativeMidiEvent ev = { 0, 0, 3, { 0, 0, 0, 0 } };
  130. while (mqueueRT.get(d1, d2, d3))
  131. {
  132. ev.data[0] = d1;
  133. ev.data[1] = d2;
  134. ev.data[2] = d3;
  135. writeMidiEvent(&ev);
  136. }
  137. }
  138. for (uint32_t i=0; i < midiEventCount; ++i)
  139. writeMidiEvent(&midiEvents[i]);
  140. }
  141. #ifndef CARLA_OS_WASM
  142. // -------------------------------------------------------------------
  143. // Pipe Server calls
  144. bool msgReceived(const char* const msg) noexcept override
  145. {
  146. if (NativePluginAndUiClass::msgReceived(msg))
  147. return true;
  148. if (std::strcmp(msg, "cc") == 0)
  149. {
  150. uint8_t cc, value;
  151. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc), true);
  152. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value), true);
  153. const CarlaMutexLocker cml(mqueue.getMutex());
  154. for (int i=0; i<16; ++i)
  155. {
  156. if (channels[i])
  157. if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc, value))
  158. break;
  159. }
  160. return true;
  161. }
  162. if (std::strcmp(msg, "cc2") == 0)
  163. {
  164. uint8_t cc1, value1, cc2, value2;
  165. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc1), true);
  166. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value1), true);
  167. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc2), true);
  168. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value2), true);
  169. const CarlaMutexLocker cml(mqueue.getMutex());
  170. for (int i=0; i<16; ++i)
  171. {
  172. if (channels[i])
  173. {
  174. if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc1, value1))
  175. break;
  176. if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc2, value2))
  177. break;
  178. }
  179. }
  180. return true;
  181. }
  182. if (std::strcmp(msg, "note") == 0)
  183. {
  184. bool onOff;
  185. uint8_t note;
  186. CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(onOff), true);
  187. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(note), true);
  188. const uint8_t status = onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF;
  189. const uint8_t velocity = onOff ? 100 : 0;
  190. const CarlaMutexLocker cml(mqueue.getMutex());
  191. for (int i=0; i<16; ++i)
  192. {
  193. if (channels[i])
  194. if (! mqueue.put(uint8_t(status | (i & MIDI_CHANNEL_BIT)), note, velocity))
  195. break;
  196. }
  197. return true;
  198. }
  199. return false;
  200. }
  201. #endif
  202. private:
  203. float params[kParamCount];
  204. bool channels[16];
  205. MIDIEventQueue<128> mqueue, mqueueRT;
  206. PluginClassEND(XYControllerPlugin)
  207. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(XYControllerPlugin)
  208. };
  209. // -----------------------------------------------------------------------
  210. static const NativePluginDescriptor notesDesc = {
  211. /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
  212. /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
  213. |NATIVE_PLUGIN_HAS_UI),
  214. /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
  215. /* audioIns */ 0,
  216. /* audioOuts */ 0,
  217. /* midiIns */ 1,
  218. /* midiOuts */ 1,
  219. /* paramIns */ 2,
  220. /* paramOuts */ 2,
  221. /* name */ "XY Controller",
  222. /* label */ "xycontroller",
  223. /* maker */ "falkTX",
  224. /* copyright */ "GNU GPL v2+",
  225. PluginDescriptorFILL(XYControllerPlugin)
  226. };
  227. // -----------------------------------------------------------------------
  228. CARLA_API_EXPORT
  229. void carla_register_native_plugin_xycontroller();
  230. CARLA_API_EXPORT
  231. void carla_register_native_plugin_xycontroller()
  232. {
  233. carla_register_native_plugin(&notesDesc);
  234. }
  235. // -----------------------------------------------------------------------