@@ -30,6 +30,15 @@ | |||
"tags": [ | |||
"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 | |||
USE_NAMESPACE_DISTRHO; | |||
// ----------------------------------------------------------------------------------------------------------- | |||
USE_NAMESPACE_DISTRHO; | |||
struct HostParameters : Module { | |||
enum ParamIds { | |||
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 Model* modelGlBars; | |||
extern Model* modelHostParameters; | |||
extern Model* modelHostTime; |
@@ -373,6 +373,7 @@ static void initStatic__Cardinal() | |||
const StaticPluginLoader spl(p, "Cardinal"); | |||
if (spl.ok()) | |||
{ | |||
p->addModel(modelGlBars); | |||
p->addModel(modelHostParameters); | |||
p->addModel(modelHostTime); | |||
} | |||
@@ -522,6 +522,20 @@ protected: | |||
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: | |||
/** | |||
Set our UI class as non-copyable and add a leak detector just in case. | |||