Created
March 17, 2025 00:21
-
-
Save Simon-L/65ac25c8caddebf11190c70b9dfea8a7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* DISTRHO Plugin Framework (DPF) | |
* Copyright (C) 2012-2019 Filipe Coelho <[email protected]> | |
* | |
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |
* or without fee is hereby granted, provided that the above copyright notice and this | |
* permission notice appear in all copies. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
*/ | |
#include "DistrhoUI.hpp" | |
#include <cstdint> | |
#include <cstdio> | |
START_NAMESPACE_DISTRHO | |
/** | |
We need the Color class from DGL. | |
*/ | |
using DGL_NAMESPACE::Color; | |
/** | |
Smooth meters a bit. | |
*/ | |
static const float kSmoothMultiplier = 3.0f; | |
// ----------------------------------------------------------------------------------------------------------- | |
class ExampleUIMeters : public UI | |
{ | |
public: | |
ExampleUIMeters() | |
: UI(900, 512), | |
// default color is green | |
fColor(93, 231, 61), | |
// which is value 0 | |
fColorValue(0), | |
// init meter values to 0 | |
fOutLeft(0.0f), | |
fOutRight(0.0f) | |
{ | |
setGeometryConstraints(32, 128, false); | |
} | |
protected: | |
/* -------------------------------------------------------------------------------------------------------- | |
* DSP/Plugin Callbacks */ | |
/** | |
A parameter has changed on the plugin side. | |
This is called by the host to inform the UI about parameter changes. | |
*/ | |
void parameterChanged(uint32_t index, float value) override | |
{ | |
switch (index) | |
{ | |
case 0: // color | |
updateColor(std::round(value)); | |
break; | |
case 1: // out-left | |
value = (fOutLeft * kSmoothMultiplier + value) / (kSmoothMultiplier + 1.0f); | |
/**/ if (value < 0.001f) value = 0.0f; | |
else if (value > 0.999f) value = 1.0f; | |
if (fOutLeft != value) | |
{ | |
fOutLeft = value; | |
repaint(); | |
} | |
break; | |
case 2: // out-right | |
value = (fOutRight * kSmoothMultiplier + value) / (kSmoothMultiplier + 1.0f); | |
/**/ if (value < 0.001f) value = 0.0f; | |
else if (value > 0.999f) value = 1.0f; | |
if (fOutRight != value) | |
{ | |
fOutRight = value; | |
repaint(); | |
} | |
break; | |
} | |
} | |
/** | |
A state has changed on the plugin side. | |
This is called by the host to inform the UI about state changes. | |
*/ | |
void stateChanged(const char*, const char*) override | |
{ | |
// nothing here | |
} | |
/* -------------------------------------------------------------------------------------------------------- | |
* Widget Callbacks */ | |
/** | |
The NanoVG drawing function. | |
*/ | |
void onNanoDisplay() override | |
{ | |
static const Color kColorBlack(0, 0, 0); | |
static const Color kColorRed(255, 0, 0); | |
static const Color kColorYellow(255, 255, 0); | |
// get meter values | |
const float outLeft(fOutLeft); | |
const float outRight(fOutRight); | |
// tell DSP side to reset meter values | |
setState("reset", ""); | |
// useful vars | |
const float halfWidth = static_cast<float>(getWidth()) * 0.05f; | |
const float redYellowHeight = static_cast<float>(getHeight())*0.2f; | |
const float yellowBaseHeight = static_cast<float>(getHeight())*0.4f; | |
const float baseBaseHeight = static_cast<float>(getHeight())*0.6f; | |
// create gradients | |
Paint fGradient1 = linearGradient(0.0f, 0.0f, 0.0f, redYellowHeight, kColorRed, kColorYellow); | |
Paint fGradient2 = linearGradient(0.0f, redYellowHeight, 0.0f, yellowBaseHeight, kColorYellow, fColor); | |
// paint left meter | |
beginPath(); | |
rect(0.0f, 0.0f, halfWidth-1.0f, redYellowHeight); | |
fillPaint(fGradient1); | |
fill(); | |
closePath(); | |
beginPath(); | |
rect(0.0f, redYellowHeight-0.5f, halfWidth-1.0f, yellowBaseHeight); | |
fillPaint(fGradient2); | |
fill(); | |
closePath(); | |
beginPath(); | |
rect(0.0f, redYellowHeight+yellowBaseHeight-1.5f, halfWidth-1.0f, baseBaseHeight); | |
fillColor(fColor); | |
fill(); | |
closePath(); | |
// paint left black matching output level | |
beginPath(); | |
rect(0.0f, 0.0f, halfWidth-1.0f, (1.0f-outLeft)*getHeight()); | |
fillColor(kColorBlack); | |
fill(); | |
closePath(); | |
// paint right meter | |
beginPath(); | |
rect(halfWidth+1.0f, 0.0f, halfWidth-2.0f, redYellowHeight); | |
fillPaint(fGradient1); | |
fill(); | |
closePath(); | |
beginPath(); | |
rect(halfWidth+1.0f, redYellowHeight-0.5f, halfWidth-2.0f, yellowBaseHeight); | |
fillPaint(fGradient2); | |
fill(); | |
closePath(); | |
beginPath(); | |
rect(halfWidth+1.0f, redYellowHeight+yellowBaseHeight-1.5f, halfWidth-2.0f, baseBaseHeight); | |
fillColor(fColor); | |
fill(); | |
closePath(); | |
// paint right black matching output level | |
beginPath(); | |
rect(halfWidth+1.0f, 0.0f, halfWidth-2.0f, (1.0f-outRight)*getHeight()); | |
fillColor(kColorBlack); | |
fill(); | |
closePath(); | |
drawImageTest(128, 16, outLeft+outRight); | |
} | |
/** | |
Mouse press event. | |
This UI will change color when clicked. | |
*/ | |
bool onMouse(const MouseEvent& ev) override | |
{ | |
// Test for left-clicked + pressed first. | |
if (ev.button != 1 || ! ev.press) | |
return false; | |
const int newColor(fColorValue == 0 ? 1 : 0); | |
updateColor(newColor); | |
setParameterValue(0, newColor); | |
return true; | |
} | |
// ------------------------------------------------------------------------------------------------------- | |
private: | |
/** | |
Color and its matching parameter value. | |
*/ | |
Color fColor; | |
int fColorValue; | |
/** | |
Meter values. | |
These are the parameter outputs from the DSP side. | |
*/ | |
float fOutLeft, fOutRight; | |
NanoImage nimg; | |
unsigned char data[640*480*4]; | |
void drawImageTest(float x, float y, float t) | |
{ | |
int i, j; | |
if (!nimg.isValid()) { | |
unsigned char* px = data; | |
for (i = 0; i < 640; i++) { | |
for (j = 0; j < 480; j++) { | |
auto r = rand() % 256; | |
px[0] = r * 0.5 * t; | |
px[1] = r * 0.5 * t; | |
px[2] = r * 0.5 * t; | |
px[3] = 255; | |
px += 4; | |
} | |
} | |
nimg = createImageFromRGBA(640, 480, data, 0); | |
} else { | |
unsigned char c = (unsigned char)((1+sinf(t))*0.5f*255.0f); | |
unsigned char* px = data; | |
for (i = 0; i < 640; i++) { | |
for (j = 0; j < 480; j++) { | |
auto r = rand() % 256; | |
px[0] = r * 0.5 * t; | |
px[1] = r * 0.5 * t; | |
px[2] = r * 0.5 * t; | |
px[3] = 255; | |
px += 4; | |
} | |
} | |
nimg.updateImage(data); | |
} | |
beginPath(); | |
rect(x, y, 640, 480); | |
fillPaint(imagePattern(x, y, 640, 480, 0, nimg, 1.0f)); | |
fill(); | |
} | |
/** | |
Update color if needed. | |
*/ | |
void updateColor(const int color) | |
{ | |
if (fColorValue == color) | |
return; | |
fColorValue = color; | |
switch (color) | |
{ | |
case METER_COLOR_GREEN: | |
fColor = Color(93, 231, 61); | |
break; | |
case METER_COLOR_BLUE: | |
fColor = Color(82, 238, 248); | |
break; | |
} | |
repaint(); | |
} | |
/** | |
Set our UI class as non-copyable and add a leak detector just in case. | |
*/ | |
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExampleUIMeters) | |
}; | |
/* ------------------------------------------------------------------------------------------------------------ | |
* UI entry point, called by DPF to create a new UI instance. */ | |
UI* createUI() | |
{ | |
return new ExampleUIMeters(); | |
} | |
// ----------------------------------------------------------------------------------------------------------- | |
END_NAMESPACE_DISTRHO |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment