Update CI version
[carla.git] / source / native-plugins / xycontroller.cpp
blob5b90a9465b90b8339d708f91c37b68d0c810357b
1 /*
2 * XY Controller UI, taken from Cadence
3 * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
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.
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.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaDefines.h"
20 #include "CarlaMIDI.h"
21 #include "CarlaNativeExtUI.hpp"
23 #include "midi-queue.hpp"
24 #include "water/text/StringArray.h"
26 // -----------------------------------------------------------------------
28 class XYControllerPlugin : public NativePluginAndUiClass
30 public:
31 enum Parameters {
32 kParamInX,
33 kParamInY,
34 kParamOutX,
35 kParamOutY,
36 kParamCount,
39 XYControllerPlugin(const NativeHostDescriptor* const host)
40 : NativePluginAndUiClass(host, "xycontroller-ui"),
41 params(),
42 channels(),
43 mqueue(),
44 mqueueRT()
46 carla_zeroStruct(params);
47 carla_zeroStruct(channels);
48 channels[0] = true;
51 protected:
52 // -------------------------------------------------------------------
53 // Plugin parameter calls
55 uint32_t getParameterCount() const override
57 return kParamCount;
60 const NativeParameter* getParameterInfo(const uint32_t index) const override
62 CARLA_SAFE_ASSERT_RETURN(index < kParamCount, nullptr);
64 static NativeParameter param;
66 int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMATABLE;
68 param.name = nullptr;
69 param.unit = "%";
70 param.ranges.def = 0.0f;
71 param.ranges.min = -100.0f;
72 param.ranges.max = 100.0f;
73 param.ranges.step = 1.0f;
74 param.ranges.stepSmall = 0.01f;
75 param.ranges.stepLarge = 10.0f;
76 param.scalePointCount = 0;
77 param.scalePoints = nullptr;
79 switch (index)
81 case kParamInX:
82 param.name = "X";
83 break;
84 case kParamInY:
85 param.name = "Y";
86 break;
87 case kParamOutX:
88 hints |= NATIVE_PARAMETER_IS_OUTPUT;
89 param.name = "Out X";
90 break;
91 case kParamOutY:
92 hints |= NATIVE_PARAMETER_IS_OUTPUT;
93 param.name = "Out Y";
94 break;
97 param.hints = static_cast<NativeParameterHints>(hints);
99 return &param;
102 float getParameterValue(const uint32_t index) const override
104 CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f);
106 return params[index];
109 // -------------------------------------------------------------------
110 // Plugin state calls
112 void setParameterValue(const uint32_t index, const float value) override
114 switch (index)
116 case kParamInX:
117 case kParamInY:
118 params[index] = value;
119 break;
123 void setCustomData(const char* const key, const char* const value) override
125 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
126 CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
128 if (std::strcmp(key, "channels") == 0)
130 const water::StringArray chans(water::StringArray::fromTokens(value, ",", ""));
132 carla_zeroStruct(channels);
134 for (const water::String *it=chans.begin(), *end=chans.end(); it != end; ++it)
136 const int ichan = std::atoi((*it).toRawUTF8());
137 CARLA_SAFE_ASSERT_INT_CONTINUE(ichan >= 1 && ichan <= 16, ichan);
139 channels[ichan-1] = true;
144 // -------------------------------------------------------------------
145 // Plugin process calls
147 void process(const float* const*, float**, const uint32_t,
148 const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
150 params[kParamOutX] = params[kParamInX];
151 params[kParamOutY] = params[kParamInY];
153 if (mqueue.isNotEmpty() && mqueueRT.tryToCopyDataFrom(mqueue))
155 uint8_t d1, d2, d3;
156 NativeMidiEvent ev = { 0, 0, 3, { 0, 0, 0, 0 } };
158 while (mqueueRT.get(d1, d2, d3))
160 ev.data[0] = d1;
161 ev.data[1] = d2;
162 ev.data[2] = d3;
163 writeMidiEvent(&ev);
167 for (uint32_t i=0; i < midiEventCount; ++i)
168 writeMidiEvent(&midiEvents[i]);
171 #ifndef CARLA_OS_WASM
172 // -------------------------------------------------------------------
173 // Pipe Server calls
175 bool msgReceived(const char* const msg) noexcept override
177 if (NativePluginAndUiClass::msgReceived(msg))
178 return true;
180 if (std::strcmp(msg, "cc") == 0)
182 uint8_t cc, value;
183 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc), true);
184 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value), true);
186 const CarlaMutexLocker cml(mqueue.getMutex());
188 for (int i=0; i<16; ++i)
190 if (channels[i])
191 if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc, value))
192 break;
195 return true;
198 if (std::strcmp(msg, "cc2") == 0)
200 uint8_t cc1, value1, cc2, value2;
201 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc1), true);
202 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value1), true);
203 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc2), true);
204 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value2), true);
206 const CarlaMutexLocker cml(mqueue.getMutex());
208 for (int i=0; i<16; ++i)
210 if (channels[i])
212 if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc1, value1))
213 break;
214 if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc2, value2))
215 break;
219 return true;
222 if (std::strcmp(msg, "note") == 0)
224 bool onOff;
225 uint8_t note;
226 CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(onOff), true);
227 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(note), true);
229 const uint8_t status = onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF;
230 const uint8_t velocity = onOff ? 100 : 0;
232 const CarlaMutexLocker cml(mqueue.getMutex());
234 for (int i=0; i<16; ++i)
236 if (channels[i])
237 if (! mqueue.put(uint8_t(status | (i & MIDI_CHANNEL_BIT)), note, velocity))
238 break;
241 return true;
244 return false;
246 #endif
248 private:
249 float params[kParamCount];
250 bool channels[16];
252 MIDIEventQueue<128> mqueue, mqueueRT;
254 PluginClassEND(XYControllerPlugin)
255 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(XYControllerPlugin)
258 // -----------------------------------------------------------------------
260 static const NativePluginDescriptor notesDesc = {
261 /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
262 /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
263 |NATIVE_PLUGIN_HAS_UI),
264 /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
265 /* audioIns */ 0,
266 /* audioOuts */ 0,
267 /* midiIns */ 1,
268 /* midiOuts */ 1,
269 /* paramIns */ 2,
270 /* paramOuts */ 2,
271 /* name */ "XY Controller",
272 /* label */ "xycontroller",
273 /* maker */ "falkTX",
274 /* copyright */ "GNU GPL v2+",
275 PluginDescriptorFILL(XYControllerPlugin)
278 // -----------------------------------------------------------------------
280 CARLA_API_EXPORT
281 void carla_register_native_plugin_xycontroller();
283 CARLA_API_EXPORT
284 void carla_register_native_plugin_xycontroller()
286 carla_register_native_plugin(&notesDesc);
289 // -----------------------------------------------------------------------