1 /*
2 * XY Controller UI, taken from Cadence
3 * Copyright (C) 2011-2020 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
18 #include "CarlaDefines.h"
19
20 #include "CarlaMIDI.h"
21 #include "CarlaNativeExtUI.hpp"
22
23 #include "midi-queue.hpp"
24 #include "water/text/StringArray.h"
25
26 // -----------------------------------------------------------------------
27
28 class XYControllerPlugin : public NativePluginAndUiClass
29 {
30 public:
31 enum Parameters {
32 kParamInX,
33 kParamInY,
34 kParamOutX,
35 kParamOutY,
36 kParamCount,
37 };
38
XYControllerPlugin(const NativeHostDescriptor * const host)39 XYControllerPlugin(const NativeHostDescriptor* const host)
40 : NativePluginAndUiClass(host, "xycontroller-ui"),
41 params(),
42 channels(),
43 mqueue(),
44 mqueueRT()
45 {
46 carla_zeroStruct(params);
47 carla_zeroStruct(channels);
48 channels[0] = true;
49 }
50
51 protected:
52 // -------------------------------------------------------------------
53 // Plugin parameter calls
54
getParameterCount() const55 uint32_t getParameterCount() const override
56 {
57 return kParamCount;
58 }
59
getParameterInfo(const uint32_t index) const60 const NativeParameter* getParameterInfo(const uint32_t index) const override
61 {
62 CARLA_SAFE_ASSERT_RETURN(index < kParamCount, nullptr);
63
64 static NativeParameter param;
65
66 int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE;
67
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;
78
79 switch (index)
80 {
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;
95 }
96
97 param.hints = static_cast<NativeParameterHints>(hints);
98
99 return ¶m;
100 }
101
getParameterValue(const uint32_t index) const102 float getParameterValue(const uint32_t index) const override
103 {
104 CARLA_SAFE_ASSERT_RETURN(index < kParamCount, 0.0f);
105
106 return params[index];
107 }
108
109 // -------------------------------------------------------------------
110 // Plugin state calls
111
setParameterValue(const uint32_t index,const float value)112 void setParameterValue(const uint32_t index, const float value) override
113 {
114 switch (index)
115 {
116 case kParamInX:
117 case kParamInY:
118 params[index] = value;
119 break;
120 }
121 }
122
setCustomData(const char * const key,const char * const value)123 void setCustomData(const char* const key, const char* const value) override
124 {
125 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
126 CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
127
128 if (std::strcmp(key, "channels") == 0)
129 {
130 const water::StringArray chans(water::StringArray::fromTokens(value, ",", ""));
131
132 carla_zeroStruct(channels);
133
134 for (const water::String *it=chans.begin(), *end=chans.end(); it != end; ++it)
135 {
136 const int ichan = std::atoi((*it).toRawUTF8());
137 CARLA_SAFE_ASSERT_INT_CONTINUE(ichan >= 1 && ichan <= 16, ichan);
138
139 channels[ichan-1] = true;
140 }
141 }
142 }
143
144 // -------------------------------------------------------------------
145 // Plugin process calls
146
process(const float * const *,float **,const uint32_t,const NativeMidiEvent * const midiEvents,const uint32_t midiEventCount)147 void process(const float* const*, float**, const uint32_t,
148 const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
149 {
150 params[kParamOutX] = params[kParamInX];
151 params[kParamOutY] = params[kParamInY];
152
153 if (mqueue.isNotEmpty() && mqueueRT.tryToCopyDataFrom(mqueue))
154 {
155 uint8_t d1, d2, d3;
156 NativeMidiEvent ev = { 0, 0, 3, { 0, 0, 0, 0 } };
157
158 while (mqueueRT.get(d1, d2, d3))
159 {
160 ev.data[0] = d1;
161 ev.data[1] = d2;
162 ev.data[2] = d3;
163 writeMidiEvent(&ev);
164 }
165 }
166
167 for (uint32_t i=0; i < midiEventCount; ++i)
168 writeMidiEvent(&midiEvents[i]);
169 }
170
171 // -------------------------------------------------------------------
172 // Pipe Server calls
173
msgReceived(const char * const msg)174 bool msgReceived(const char* const msg) noexcept override
175 {
176 if (NativePluginAndUiClass::msgReceived(msg))
177 return true;
178
179 if (std::strcmp(msg, "cc") == 0)
180 {
181 uint8_t cc, value;
182 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc), true);
183 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value), true);
184
185 const CarlaMutexLocker cml(mqueue.getMutex());
186
187 for (int i=0; i<16; ++i)
188 {
189 if (channels[i])
190 if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc, value))
191 break;
192 }
193
194 return true;
195 }
196
197 if (std::strcmp(msg, "cc2") == 0)
198 {
199 uint8_t cc1, value1, cc2, value2;
200 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc1), true);
201 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value1), true);
202 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(cc2), true);
203 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(value2), true);
204
205 const CarlaMutexLocker cml(mqueue.getMutex());
206
207 for (int i=0; i<16; ++i)
208 {
209 if (channels[i])
210 {
211 if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc1, value1))
212 break;
213 if (! mqueue.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)), cc2, value2))
214 break;
215 }
216 }
217
218 return true;
219 }
220
221 if (std::strcmp(msg, "note") == 0)
222 {
223 bool onOff;
224 uint8_t note;
225 CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(onOff), true);
226 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(note), true);
227
228 const uint8_t status = onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF;
229 const uint8_t velocity = onOff ? 100 : 0;
230
231 const CarlaMutexLocker cml(mqueue.getMutex());
232
233 for (int i=0; i<16; ++i)
234 {
235 if (channels[i])
236 if (! mqueue.put(uint8_t(status | (i & MIDI_CHANNEL_BIT)), note, velocity))
237 break;
238 }
239
240 return true;
241 }
242
243 return false;
244 }
245
246 private:
247 float params[kParamCount];
248 bool channels[16];
249
250 MIDIEventQueue<128> mqueue, mqueueRT;
251
252 PluginClassEND(XYControllerPlugin)
253 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(XYControllerPlugin)
254 };
255
256 // -----------------------------------------------------------------------
257
258 static const NativePluginDescriptor notesDesc = {
259 /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
260 /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
261 |NATIVE_PLUGIN_HAS_UI),
262 /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
263 /* audioIns */ 0,
264 /* audioOuts */ 0,
265 /* midiIns */ 1,
266 /* midiOuts */ 1,
267 /* paramIns */ 2,
268 /* paramOuts */ 2,
269 /* name */ "XY Controller",
270 /* label */ "xycontroller",
271 /* maker */ "falkTX",
272 /* copyright */ "GNU GPL v2+",
273 PluginDescriptorFILL(XYControllerPlugin)
274 };
275
276 // -----------------------------------------------------------------------
277
278 CARLA_EXPORT
279 void carla_register_native_plugin_xycontroller();
280
281 CARLA_EXPORT
carla_register_native_plugin_xycontroller()282 void carla_register_native_plugin_xycontroller()
283 {
284 carla_register_native_plugin(¬esDesc);
285 }
286
287 // -----------------------------------------------------------------------
288