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
39 XYControllerPlugin(const NativeHostDescriptor
* const host
)
40 : NativePluginAndUiClass(host
, "xycontroller-ui"),
46 carla_zeroStruct(params
);
47 carla_zeroStruct(channels
);
52 // -------------------------------------------------------------------
53 // Plugin parameter calls
55 uint32_t getParameterCount() const override
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
;
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;
88 hints
|= NATIVE_PARAMETER_IS_OUTPUT
;
92 hints
|= NATIVE_PARAMETER_IS_OUTPUT
;
97 param
.hints
= static_cast<NativeParameterHints
>(hints
);
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
118 params
[index
] = value
;
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
))
156 NativeMidiEvent ev
= { 0, 0, 3, { 0, 0, 0, 0 } };
158 while (mqueueRT
.get(d1
, d2
, d3
))
167 for (uint32_t i
=0; i
< midiEventCount
; ++i
)
168 writeMidiEvent(&midiEvents
[i
]);
171 #ifndef CARLA_OS_WASM
172 // -------------------------------------------------------------------
175 bool msgReceived(const char* const msg
) noexcept override
177 if (NativePluginAndUiClass::msgReceived(msg
))
180 if (std::strcmp(msg
, "cc") == 0)
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
)
191 if (! mqueue
.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE
| (i
& MIDI_CHANNEL_BIT
)), cc
, value
))
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
)
212 if (! mqueue
.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE
| (i
& MIDI_CHANNEL_BIT
)), cc1
, value1
))
214 if (! mqueue
.put(uint8_t(MIDI_STATUS_CONTROL_CHANGE
| (i
& MIDI_CHANNEL_BIT
)), cc2
, value2
))
222 if (std::strcmp(msg
, "note") == 0)
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
)
237 if (! mqueue
.put(uint8_t(status
| (i
& MIDI_CHANNEL_BIT
)), note
, velocity
))
249 float params
[kParamCount
];
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
,
271 /* name */ "XY Controller",
272 /* label */ "xycontroller",
273 /* maker */ "falkTX",
274 /* copyright */ "GNU GPL v2+",
275 PluginDescriptorFILL(XYControllerPlugin
)
278 // -----------------------------------------------------------------------
281 void carla_register_native_plugin_xycontroller();
284 void carla_register_native_plugin_xycontroller()
286 carla_register_native_plugin(¬esDesc
);
289 // -----------------------------------------------------------------------