@@ -30,6 +30,15 @@ | |||||
"tags": [ | "tags": [ | ||||
"Utility" | "Utility" | ||||
] | ] | ||||
}, | |||||
{ | |||||
"slug": "glBars", | |||||
"disabled": false, | |||||
"name": "glBars", | |||||
"description": "OpenGL bars visualization, as seen in XMMS and XBMC/Kodi", | |||||
"tags": [ | |||||
"Visual" | |||||
] | |||||
} | } | ||||
] | ] | ||||
} | } |
@@ -0,0 +1,128 @@ | |||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
<svg | |||||
width="131.44501mm" | |||||
height="128.5mm" | |||||
viewBox="0 0 131.44501 128.5" | |||||
version="1.1" | |||||
id="svg4620" | |||||
inkscape:version="1.1.1 (c3084ef, 2021-09-22)" | |||||
sodipodi:docname="glBars.svg" | |||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||||
xmlns="http://www.w3.org/2000/svg" | |||||
xmlns:svg="http://www.w3.org/2000/svg" | |||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
xmlns:cc="http://creativecommons.org/ns#" | |||||
xmlns:dc="http://purl.org/dc/elements/1.1/"> | |||||
<defs | |||||
id="defs4614"> | |||||
<linearGradient | |||||
gradientTransform="matrix(2.8749528,0,0,1,5.1153789e-6,168.49892)" | |||||
inkscape:collect="always" | |||||
xlink:href="#linearGradient869" | |||||
id="linearGradient871" | |||||
x1="22.450642" | |||||
y1="0.64095056" | |||||
x2="22.450642" | |||||
y2="129.73215" | |||||
gradientUnits="userSpaceOnUse" /> | |||||
<linearGradient | |||||
inkscape:collect="always" | |||||
id="linearGradient869"> | |||||
<stop | |||||
style="stop-color:#181919;stop-opacity:1;" | |||||
offset="0" | |||||
id="stop865" /> | |||||
<stop | |||||
style="stop-color:#212222;stop-opacity:1" | |||||
offset="1" | |||||
id="stop867" /> | |||||
</linearGradient> | |||||
<style | |||||
id="style6" | |||||
type="text/css"> | |||||
.str0 {stroke:#565656;stroke-width:0.0966867} | |||||
.str1 {stroke:#4F4F4F;stroke-width:0.193345} | |||||
.fil0 {fill:none} | |||||
.fil2 {fill:#2B2A29} | |||||
.fil1 {fill:#6B6B6B} | |||||
</style> | |||||
</defs> | |||||
<sodipodi:namedview | |||||
id="base" | |||||
pagecolor="#ffffff" | |||||
bordercolor="#666666" | |||||
borderopacity="1.0" | |||||
inkscape:pageopacity="0.0" | |||||
inkscape:pageshadow="2" | |||||
inkscape:zoom="5.6568543" | |||||
inkscape:cx="15.556349" | |||||
inkscape:cy="51.176853" | |||||
inkscape:document-units="mm" | |||||
inkscape:current-layer="layer1" | |||||
showgrid="false" | |||||
inkscape:window-width="1229" | |||||
inkscape:window-height="667" | |||||
inkscape:window-x="51" | |||||
inkscape:window-y="25" | |||||
inkscape:window-maximized="1" | |||||
inkscape:pagecheckerboard="0" | |||||
width="45.72mm" | |||||
units="in" /> | |||||
<metadata | |||||
id="metadata4617"> | |||||
<rdf:RDF> | |||||
<cc:Work | |||||
rdf:about=""> | |||||
<dc:format>image/svg+xml</dc:format> | |||||
<dc:type | |||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||||
</cc:Work> | |||||
</rdf:RDF> | |||||
</metadata> | |||||
<g | |||||
inkscape:label="Layer 1" | |||||
inkscape:groupmode="layer" | |||||
id="layer1" | |||||
transform="translate(0,-168.5)"> | |||||
<rect | |||||
style="opacity:1;fill:url(#linearGradient871);fill-opacity:1;stroke-width:0.533853;stroke-miterlimit:4;stroke-dasharray:none" | |||||
id="rect815" | |||||
width="131.44411" | |||||
height="128.49823" | |||||
x="0" | |||||
y="168.50089" /> | |||||
<g | |||||
style="fill-rule:evenodd" | |||||
id="g5299" | |||||
transform="matrix(6.342689,0,0,6.342689,1.7430866,175.6457)"> | |||||
<g | |||||
transform="translate(-1.6191379e-5,-0.08553947)" | |||||
id="Layer_x0020_1" | |||||
inkscape:label="Layer 1" | |||||
inkscape:groupmode="layer"> | |||||
<metadata | |||||
id="CorelCorpID_0Corel-Layer" /> | |||||
<circle | |||||
style="fill:none;stroke:#ffffff;stroke-width:0.0966867;stroke-opacity:1" | |||||
id="circle10" | |||||
r="0.15916" | |||||
cy="0.61075097" | |||||
cx="0.525226" | |||||
class="fil0 str0" /> | |||||
<circle | |||||
style="fill:none;stroke:#ffffff;stroke-width:0.193345;stroke-opacity:1" | |||||
id="circle12" | |||||
r="0.42853901" | |||||
cy="0.61075097" | |||||
cx="0.525226" | |||||
class="fil0 str1" /> | |||||
</g> | |||||
</g> | |||||
</g> | |||||
</svg> |
@@ -38,10 +38,10 @@ struct CardinalPluginContext : rack::Context { | |||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
USE_NAMESPACE_DISTRHO; | |||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
USE_NAMESPACE_DISTRHO; | |||||
struct HostParameters : Module { | struct HostParameters : Module { | ||||
enum ParamIds { | enum ParamIds { | ||||
NUM_PARAMS | NUM_PARAMS | ||||
@@ -0,0 +1,99 @@ | |||||
/* | |||||
* DISTRHO Cardinal Plugin | |||||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU General Public License as | |||||
* published by the Free Software Foundation; either version 3 of | |||||
* the License, or any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* For a full copy of the GNU General Public License see the LICENSE file. | |||||
*/ | |||||
#include "glBars.hpp" | |||||
#define SAMPLES_PER_DRAW 256 | |||||
struct glBarsModule : Module { | |||||
enum ParamIds { | |||||
NUM_PARAMS | |||||
}; | |||||
enum InputIds { | |||||
IN1_INPUT, | |||||
NUM_INPUTS | |||||
}; | |||||
enum OutputIds { | |||||
NUM_OUTPUTS | |||||
}; | |||||
enum LightIds { | |||||
NUM_LIGHTS | |||||
}; | |||||
glBarsState state; | |||||
float audioData[SAMPLES_PER_DRAW]; | |||||
uint audioDataFill = 0; | |||||
glBarsModule() { | |||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); | |||||
} | |||||
void process(const ProcessArgs&) override { | |||||
audioData[audioDataFill++] = inputs[IN1_INPUT].getVoltage(); | |||||
if (audioDataFill == SAMPLES_PER_DRAW) { | |||||
audioDataFill = 0; | |||||
state.AudioData(audioData, SAMPLES_PER_DRAW); | |||||
} | |||||
} | |||||
}; | |||||
struct glBarsRendererWidget : OpenGlWidget { | |||||
glBarsModule* const glBars; | |||||
glBarsRendererWidget(glBarsModule* const module) | |||||
: glBars(module) {} | |||||
void drawFramebuffer() override { | |||||
math::Vec fbSize = getFramebufferSize(); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0.0, fbSize.x, fbSize.y, 0.0, 0.0, 1.0); | |||||
glViewport(0.0, 0.0, fbSize.x, fbSize.y); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
// glDisable(GL_CULL_FACE); | |||||
// glDisable(GL_STENCIL_TEST); | |||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||||
glBars->state.Render(); | |||||
} | |||||
}; | |||||
struct glBarsWidget : ModuleWidget { | |||||
glBarsRendererWidget* const glBarsRenderer; | |||||
glBarsWidget(glBarsModule* const module) | |||||
: glBarsRenderer(new glBarsRendererWidget(module)) | |||||
{ | |||||
setModule(module); | |||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/glBars.svg"))); | |||||
addChild(createWidget<ScrewSilver>(Vec(0, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); | |||||
glBarsRenderer->box.pos = Vec(2 * RACK_GRID_WIDTH, 0); | |||||
glBarsRenderer->box.size = Vec(box.size.x - 2 * RACK_GRID_WIDTH, box.size.y); | |||||
addChild(glBarsRenderer); | |||||
addInput(createInput<PJ301MPort>(Vec(3, 54), module, glBarsModule::IN1_INPUT)); | |||||
} | |||||
}; | |||||
Model* modelGlBars = createModel<glBarsModule, glBarsWidget>("glBars"); |
@@ -0,0 +1,234 @@ | |||||
/* | |||||
* DISTRHO glBars Plugin based on XMMS/XBMC "GL Bars" | |||||
* Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies | |||||
* Copyright (C) 2000 Christian Zander <phoenix@minion.de> | |||||
* Copyright (C) 2015 Nedko Arnaudov | |||||
* Copyright (C) 2016-2019 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* For a full copy of the license see the LICENSE file. | |||||
*/ | |||||
#ifndef GLBARS_STATE_HPP_INCLUDED | |||||
#define GLBARS_STATE_HPP_INCLUDED | |||||
#include "plugin.hpp" | |||||
static inline | |||||
void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) | |||||
{ | |||||
if (y1 == y2) | |||||
{ | |||||
glVertex3f(x1, y1, z1); | |||||
glVertex3f(x2, y1, z1); | |||||
glVertex3f(x2, y2, z2); | |||||
glVertex3f(x2, y2, z2); | |||||
glVertex3f(x1, y2, z2); | |||||
glVertex3f(x1, y1, z1); | |||||
} | |||||
else | |||||
{ | |||||
glVertex3f(x1, y1, z1); | |||||
glVertex3f(x2, y1, z2); | |||||
glVertex3f(x2, y2, z2); | |||||
glVertex3f(x2, y2, z2); | |||||
glVertex3f(x1, y2, z1); | |||||
glVertex3f(x1, y1, z1); | |||||
} | |||||
} | |||||
static inline | |||||
void draw_bar(GLenum mode, GLfloat x_offset, GLfloat z_offset, GLfloat height, GLfloat red, GLfloat green, GLfloat blue) | |||||
{ | |||||
const GLfloat width = 0.1; | |||||
if (mode == GL_POINT) | |||||
glColor3f(0.2, 1.0, 0.2); | |||||
if (mode != GL_POINT) | |||||
{ | |||||
glColor3f(red,green,blue); | |||||
draw_rectangle(x_offset, height, z_offset, x_offset + width, height, z_offset + 0.1); | |||||
} | |||||
draw_rectangle(x_offset, 0, z_offset, x_offset + width, 0, z_offset + 0.1); | |||||
if (mode != GL_POINT) | |||||
{ | |||||
glColor3f(0.5 * red, 0.5 * green, 0.5 * blue); | |||||
draw_rectangle(x_offset, 0.0, z_offset + 0.1, x_offset + width, height, z_offset + 0.1); | |||||
} | |||||
draw_rectangle(x_offset, 0.0, z_offset, x_offset + width, height, z_offset ); | |||||
if (mode != GL_POINT) | |||||
{ | |||||
glColor3f(0.25 * red, 0.25 * green, 0.25 * blue); | |||||
draw_rectangle(x_offset, 0.0, z_offset , x_offset, height, z_offset + 0.1); | |||||
} | |||||
draw_rectangle(x_offset + width, 0.0, z_offset , x_offset + width, height, z_offset + 0.1); | |||||
} | |||||
struct glBarsState { | |||||
GLenum g_mode; | |||||
GLfloat x_angle, x_speed; | |||||
GLfloat y_angle, y_speed; | |||||
GLfloat z_angle, z_speed; | |||||
GLfloat heights[16][16], cHeights[16][16], scale; | |||||
GLfloat hSpeed; | |||||
glBarsState() | |||||
{ | |||||
g_mode = GL_FILL; | |||||
x_angle = 20.0; | |||||
x_speed = 0.0; | |||||
y_angle = 15.0; // was 45 | |||||
y_speed = 0.5; | |||||
z_angle = 0.0; | |||||
z_speed = 0.0; | |||||
// Set "Bar Height" | |||||
scale = 1.f / log(256.f); // "Default" / standard | |||||
//scale = 2.f / log(256.f); // "Big" | |||||
//scale = 3.f / log(256.f); // "Very Big" / real big | |||||
//scale = 0.33f / log(256.f); // unused | |||||
//scale = 0.5f / log(256.f); // "Small" | |||||
// Set "Speed" | |||||
//hSpeed = 0.025f; // "Slow" | |||||
hSpeed = 0.0125f; // "Default" | |||||
//hSpeed = 0.1f; // "Fast" | |||||
//hSpeed = 0.2f; // "Very Fast" | |||||
//hSpeed = 0.05f; // "Very Slow" | |||||
for (int x = 0; x < 16; x++) | |||||
{ | |||||
for (int y = 0; y < 16; y++) | |||||
cHeights[y][x] = heights[y][x] = 0; | |||||
} | |||||
} | |||||
void drawBars() | |||||
{ | |||||
GLfloat x_offset, z_offset, r_base, b_base; | |||||
glClear(GL_DEPTH_BUFFER_BIT); | |||||
glPushMatrix(); | |||||
glTranslatef(0.0,-0.5,-5.0); | |||||
glRotatef(x_angle,1.0,0.0,0.0); | |||||
glRotatef(y_angle,0.0,1.0,0.0); | |||||
glRotatef(z_angle,0.0,0.0,1.0); | |||||
glPolygonMode(GL_FRONT_AND_BACK, g_mode); | |||||
glBegin(GL_TRIANGLES); | |||||
for (int y = 0; y < 16; y++) | |||||
{ | |||||
z_offset = -1.6 + ((15 - y) * 0.2); | |||||
b_base = y * (1.0 / 15); | |||||
r_base = 1.0 - b_base; | |||||
for (int x = 0; x < 16; x++) | |||||
{ | |||||
x_offset = -1.6 + ((float)x * 0.2); | |||||
if (::fabs(cHeights[y][x]-heights[y][x])>hSpeed) | |||||
{ | |||||
if (cHeights[y][x]<heights[y][x]) | |||||
cHeights[y][x] += hSpeed; | |||||
else | |||||
cHeights[y][x] -= hSpeed; | |||||
} | |||||
draw_bar(g_mode, x_offset, z_offset, | |||||
cHeights[y][x], r_base - (float(x) * (r_base / 15.0)), | |||||
(float)x * (1.0 / 15), b_base /*, 16*y+x*/); | |||||
} | |||||
} | |||||
glEnd(); | |||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | |||||
glPopMatrix(); | |||||
} | |||||
void Render() | |||||
{ | |||||
glDisable(GL_BLEND); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glPushMatrix(); | |||||
glLoadIdentity(); | |||||
glFrustum(-1, 1, -1, 1, 1.5, 10); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glPushMatrix(); | |||||
glLoadIdentity(); | |||||
glEnable(GL_DEPTH_TEST); | |||||
glDepthFunc(GL_LESS); | |||||
//glPolygonMode(GL_FRONT, GL_FILL); | |||||
//glPolygonMode(GL_BACK, GL_FILL); | |||||
x_angle += x_speed; | |||||
if (x_angle >= 360.0) | |||||
x_angle -= 360.0; | |||||
y_angle += y_speed; | |||||
if (y_angle >= 360.0) | |||||
y_angle -= 360.0; | |||||
z_angle += z_speed; | |||||
if (z_angle >= 360.0) | |||||
z_angle -= 360.0; | |||||
drawBars(); | |||||
glPopMatrix(); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glPopMatrix(); | |||||
glDisable(GL_DEPTH_TEST); | |||||
glEnable(GL_BLEND); | |||||
} | |||||
void AudioData(const float* pAudioData, int iAudioDataLength) | |||||
{ | |||||
const int xscale[] = {0, 1, 2, 3, 5, 7, 10, 14, 20, 28, 40, 54, 74, 101, 137, 187, 255}; | |||||
GLfloat val; | |||||
for (int y = 15; y > 0; y--) | |||||
{ | |||||
for (int i = 0; i < 16; i++) | |||||
heights[y][i] = heights[y - 1][i]; | |||||
} | |||||
for (int i = 0; i < 16; i++) | |||||
{ | |||||
int y = 0; | |||||
for (int c = xscale[i]; c < xscale[i + 1]; c++) | |||||
{ | |||||
if (c<iAudioDataLength) | |||||
{ | |||||
if ((int)(pAudioData[c] * (INT16_MAX)) > y) | |||||
y = (int)(pAudioData[c] * (INT16_MAX)); | |||||
} | |||||
else | |||||
{ | |||||
continue; | |||||
} | |||||
} | |||||
y >>= 7; | |||||
if (y > 0) | |||||
val = (logf(y) * scale); | |||||
else | |||||
val = 0; | |||||
heights[0][i] = val; | |||||
} | |||||
} | |||||
}; | |||||
#endif // GLBARS_STATE_HPP_INCLUDED |
@@ -23,5 +23,6 @@ using namespace rack; | |||||
extern Plugin* pluginInstance; | extern Plugin* pluginInstance; | ||||
extern Model* modelGlBars; | |||||
extern Model* modelHostParameters; | extern Model* modelHostParameters; | ||||
extern Model* modelHostTime; | extern Model* modelHostTime; |
@@ -373,6 +373,7 @@ static void initStatic__Cardinal() | |||||
const StaticPluginLoader spl(p, "Cardinal"); | const StaticPluginLoader spl(p, "Cardinal"); | ||||
if (spl.ok()) | if (spl.ok()) | ||||
{ | { | ||||
p->addModel(modelGlBars); | |||||
p->addModel(modelHostParameters); | p->addModel(modelHostParameters); | ||||
p->addModel(modelHostTime); | p->addModel(modelHostTime); | ||||
} | } | ||||
@@ -522,6 +522,20 @@ protected: | |||||
fContext->patch->loadAction(filename); | fContext->patch->loadAction(filename); | ||||
} | } | ||||
#if 0 | |||||
void uiReshape(const uint width, const uint height) override | |||||
{ | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0.0, width, 0.0, height, -1.0, 1.0); | |||||
glViewport(0, 0, width, height); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
} | |||||
#endif | |||||
private: | private: | ||||
/** | /** | ||||
Set our UI class as non-copyable and add a leak detector just in case. | Set our UI class as non-copyable and add a leak detector just in case. | ||||