1 /*
2 * Carla Native Plugins
3 * Copyright (C) 2012-2019 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 "CarlaMathUtils.hpp"
21 #include "CarlaNativeExtUI.hpp"
22
23 #include "water/maths/MathsFunctions.h"
24
25 using water::roundToIntAccurate;
26
27 // -----------------------------------------------------------------------
28
29 class BigMeterPlugin : public NativePluginAndUiClass
30 {
31 public:
BigMeterPlugin(const NativeHostDescriptor * const host)32 BigMeterPlugin(const NativeHostDescriptor* const host)
33 : NativePluginAndUiClass(host, "bigmeter-ui"),
34 fColor(1),
35 fStyle(1),
36 fOutLeft(0.0f),
37 fOutRight(0.0f),
38 fInlineDisplay() {}
39
40 protected:
41 // -------------------------------------------------------------------
42 // Plugin parameter calls
43
getParameterCount() const44 uint32_t getParameterCount() const override
45 {
46 return 4;
47 }
48
getParameterInfo(const uint32_t index) const49 const NativeParameter* getParameterInfo(const uint32_t index) const override
50 {
51 CARLA_SAFE_ASSERT_RETURN(index < 4, nullptr);
52
53 static NativeParameter param;
54 static NativeParameterScalePoint scalePoints[3];
55
56 int hints = NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_AUTOMABLE;
57
58 param.name = nullptr;
59 param.unit = nullptr;
60 param.ranges.def = 0.0f;
61 param.ranges.min = 0.0f;
62 param.ranges.max = 1.0f;
63 param.ranges.step = 1.0f;
64 param.ranges.stepSmall = 1.0f;
65 param.ranges.stepLarge = 1.0f;
66 param.scalePointCount = 0;
67 param.scalePoints = nullptr;
68
69 switch (index)
70 {
71 case 0:
72 hints |= NATIVE_PARAMETER_IS_INTEGER|NATIVE_PARAMETER_USES_SCALEPOINTS;
73 param.name = "Color";
74 param.ranges.def = 1.0f;
75 param.ranges.min = 1.0f;
76 param.ranges.max = 2.0f;
77 scalePoints[0].value = 1.0f;
78 scalePoints[0].label = "Green";
79 scalePoints[1].value = 2.0f;
80 scalePoints[1].label = "Blue";
81 param.scalePointCount = 2;
82 param.scalePoints = scalePoints;
83 break;
84 case 1:
85 hints |= NATIVE_PARAMETER_IS_INTEGER|NATIVE_PARAMETER_USES_SCALEPOINTS;
86 param.name = "Style";
87 param.ranges.def = 1.0f;
88 param.ranges.min = 1.0f;
89 param.ranges.max = 3.0f;
90 scalePoints[0].value = 1.0f;
91 scalePoints[0].label = "Default";
92 scalePoints[1].value = 2.0f;
93 scalePoints[1].label = "OpenAV";
94 scalePoints[2].value = 3.0f;
95 scalePoints[2].label = "RNCBC";
96 param.scalePointCount = 3;
97 param.scalePoints = scalePoints;
98 break;
99 case 2:
100 hints |= NATIVE_PARAMETER_IS_OUTPUT;
101 param.name = "Out Left";
102 break;
103 case 3:
104 hints |= NATIVE_PARAMETER_IS_OUTPUT;
105 param.name = "Out Right";
106 break;
107 }
108
109 param.hints = static_cast<NativeParameterHints>(hints);
110
111 return ¶m;
112 }
113
getParameterValue(const uint32_t index) const114 float getParameterValue(const uint32_t index) const override
115 {
116 switch (index)
117 {
118 case 0:
119 return float(fColor);
120 case 1:
121 return float(fStyle);
122 case 2:
123 return fOutLeft;
124 case 3:
125 return fOutRight;
126 default:
127 return 0.0f;
128 }
129 }
130
131 // -------------------------------------------------------------------
132 // Plugin state calls
133
setParameterValue(const uint32_t index,const float value)134 void setParameterValue(const uint32_t index, const float value) override
135 {
136 switch (index)
137 {
138 case 0:
139 fColor = roundToIntAccurate(value);
140 break;
141 case 1:
142 fStyle = roundToIntAccurate(value);
143 break;
144 default:
145 break;
146 }
147 }
148
149 // -------------------------------------------------------------------
150 // Plugin process calls
151
activate()152 void activate() override
153 {
154 fOutLeft = 0.0f;
155 fOutRight = 0.0f;
156 }
157
process(const float * const * inputs,float **,const uint32_t frames,const NativeMidiEvent * const,const uint32_t)158 void process(const float* const* inputs, float**, const uint32_t frames,
159 const NativeMidiEvent* const, const uint32_t) override
160 {
161 fOutLeft = carla_findMaxNormalizedFloat(inputs[0], frames);
162 fOutRight = carla_findMaxNormalizedFloat(inputs[1], frames);
163
164 bool needsInlineRender = fInlineDisplay.pending < 0;
165
166 if (carla_isNotEqual(fOutLeft, fInlineDisplay.lastLeft))
167 {
168 fInlineDisplay.lastLeft = fOutLeft;
169 needsInlineRender = true;
170 }
171
172 if (carla_isNotEqual(fOutRight, fInlineDisplay.lastRight))
173 {
174 fInlineDisplay.lastRight = fOutRight;
175 needsInlineRender = true;
176 }
177
178 if (needsInlineRender && fInlineDisplay.pending != 1 && fInlineDisplay.pending != 2)
179 {
180 fInlineDisplay.pending = 1;
181 hostRequestIdle();
182 }
183 }
184
185 // -------------------------------------------------------------------
186 // Plugin dispatcher calls
187
idle()188 void idle() override
189 {
190 if (fInlineDisplay.pending == 1)
191 {
192 fInlineDisplay.pending = 2;
193 hostQueueDrawInlineDisplay();
194 }
195 }
196
renderInlineDisplay(const uint32_t rwidth,const uint32_t height)197 const NativeInlineDisplayImageSurface* renderInlineDisplay(const uint32_t rwidth, const uint32_t height) override
198 {
199 CARLA_SAFE_ASSERT_RETURN(rwidth > 0 && height > 0, nullptr);
200
201 const uint32_t width = rwidth == height ? height / 6 : rwidth;
202 const size_t stride = width * 4;
203 const size_t dataSize = stride * height;
204
205 uchar* data = fInlineDisplay.data;
206
207 if (fInlineDisplay.dataSize < dataSize || data == nullptr)
208 {
209 delete[] data;
210 data = new uchar[dataSize];
211 std::memset(data, 0, dataSize);
212 fInlineDisplay.data = data;
213 fInlineDisplay.dataSize = dataSize;
214 }
215
216 std::memset(data, 0, dataSize);
217
218 fInlineDisplay.width = static_cast<int>(width);
219 fInlineDisplay.height = static_cast<int>(height);
220 fInlineDisplay.stride = static_cast<int>(stride);
221
222 const uint heightValueLeft = static_cast<uint>(fInlineDisplay.lastLeft * static_cast<float>(height));
223 const uint heightValueRight = static_cast<uint>(fInlineDisplay.lastRight * static_cast<float>(height));
224
225 for (uint h=0; h < height; ++h)
226 {
227 for (uint w=0; w < width; ++w)
228 {
229 // data[h * stride + w * 4 + 0] = 0;
230 // data[h * stride + w * 4 + 1] = 255;
231 // data[h * stride + w * 4 + 2] = 0;
232 data[h * stride + w * 4 + 3] = 160;
233 }
234 }
235
236 for (uint h=0; h < heightValueLeft; ++h)
237 {
238 const uint h2 = height - h - 1;
239
240 for (uint w=0; w < width / 2; ++w)
241 {
242 data[h2 * stride + w * 4 + 0] = 200;
243 data[h2 * stride + w * 4 + 1] = 0;
244 data[h2 * stride + w * 4 + 2] = 0;
245 data[h2 * stride + w * 4 + 3] = 255;
246 }
247 }
248
249 for (uint h=0; h < heightValueRight; ++h)
250 {
251 const uint h2 = height - h - 1;
252
253 for (uint w=width / 2; w < width; ++w)
254 {
255 data[h2 * stride + w * 4 + 0] = 200;
256 data[h2 * stride + w * 4 + 1] = 0;
257 data[h2 * stride + w * 4 + 2] = 0;
258 data[h2 * stride + w * 4 + 3] = 255;
259 }
260 }
261
262 // draw 1px border
263 for (uint w=0; w < width; ++w)
264 {
265 // data[w * 4 + 0] = 0;
266 // data[w * 4 + 1] = 0;
267 // data[w * 4 + 2] = 255;
268 data[w * 4 + 3] = 120;
269
270 // data[(height - 1) * stride + w * 4 + 0] = 0;
271 // data[(height - 1) * stride + w * 4 + 1] = 0;
272 // data[(height - 1) * stride + w * 4 + 2] = 255;
273 data[(height - 1) * stride + w * 4 + 3] = 120;
274 }
275
276 for (uint h=0; h < height; ++h)
277 {
278 // data[h * stride + 0] = 0;
279 // data[h * stride + 1] = 0;
280 // data[h * stride + 2] = 255;
281 data[h * stride + 3] = 120;
282
283 data[h * stride + (width / 2) * 4 + 0] = 0;
284 data[h * stride + (width / 2) * 4 + 1] = 0;
285 data[h * stride + (width / 2) * 4 + 2] = 0;
286 data[h * stride + (width / 2) * 4 + 3] = 160;
287
288 // data[h * stride + (width - 1) * 4 + 0] = 0;
289 // data[h * stride + (width - 1) * 4 + 1] = 0;
290 // data[h * stride + (width - 1) * 4 + 2] = 255;
291 data[h * stride + (width - 1) * 4 + 3] = 120;
292 }
293
294 fInlineDisplay.pending = rwidth == height ? -1 : 0;
295 return (NativeInlineDisplayImageSurface*)(NativeInlineDisplayImageSurfaceCompat*)&fInlineDisplay;
296 }
297
298 private:
299 int fColor, fStyle;
300 float fOutLeft, fOutRight;
301
302 struct InlineDisplay : NativeInlineDisplayImageSurfaceCompat {
303 float lastLeft;
304 float lastRight;
305 volatile int pending;
306
InlineDisplayBigMeterPlugin::InlineDisplay307 InlineDisplay()
308 : NativeInlineDisplayImageSurfaceCompat(),
309 lastLeft(0.0f),
310 lastRight(0.0f),
311 pending(0) {}
312
~InlineDisplayBigMeterPlugin::InlineDisplay313 ~InlineDisplay()
314 {
315 if (data != nullptr)
316 {
317 delete[] data;
318 data = nullptr;
319 }
320 }
321
322 CARLA_DECLARE_NON_COPY_STRUCT(InlineDisplay)
323 CARLA_PREVENT_HEAP_ALLOCATION
324 } fInlineDisplay;
325
326 PluginClassEND(BigMeterPlugin)
327 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BigMeterPlugin)
328 };
329
330 // -----------------------------------------------------------------------
331
332 static const NativePluginDescriptor bigmeterDesc = {
333 /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY,
334 /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
335 |NATIVE_PLUGIN_HAS_INLINE_DISPLAY
336 |NATIVE_PLUGIN_HAS_UI
337 |NATIVE_PLUGIN_REQUESTS_IDLE),
338 /* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING,
339 /* audioIns */ 2,
340 /* audioOuts */ 0,
341 /* midiIns */ 0,
342 /* midiOuts */ 0,
343 /* paramIns */ 2,
344 /* paramOuts */ 2,
345 /* name */ "Big Meter",
346 /* label */ "bigmeter",
347 /* maker */ "falkTX",
348 /* copyright */ "GNU GPL v2+",
349 PluginDescriptorFILL(BigMeterPlugin)
350 };
351
352 // -----------------------------------------------------------------------
353
354 CARLA_EXPORT
355 void carla_register_native_plugin_bigmeter();
356
357 CARLA_EXPORT
carla_register_native_plugin_bigmeter()358 void carla_register_native_plugin_bigmeter()
359 {
360 carla_register_native_plugin(&bigmeterDesc);
361 }
362
363 // -----------------------------------------------------------------------
364