diff --git a/plugins/Cardinal/plugin.json b/plugins/Cardinal/plugin.json
index 22f67f4..16c5b4f 100644
--- a/plugins/Cardinal/plugin.json
+++ b/plugins/Cardinal/plugin.json
@@ -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"
+ ]
}
]
}
diff --git a/plugins/Cardinal/res/glBars.svg b/plugins/Cardinal/res/glBars.svg
new file mode 100644
index 0000000..7120e1c
--- /dev/null
+++ b/plugins/Cardinal/res/glBars.svg
@@ -0,0 +1,128 @@
+
+
+
+
diff --git a/plugins/Cardinal/src/HostParameters.cpp b/plugins/Cardinal/src/HostParameters.cpp
index d88f5a6..a017b5a 100644
--- a/plugins/Cardinal/src/HostParameters.cpp
+++ b/plugins/Cardinal/src/HostParameters.cpp
@@ -38,10 +38,10 @@ struct CardinalPluginContext : rack::Context {
END_NAMESPACE_DISTRHO
-USE_NAMESPACE_DISTRHO;
-
// -----------------------------------------------------------------------------------------------------------
+USE_NAMESPACE_DISTRHO;
+
struct HostParameters : Module {
enum ParamIds {
NUM_PARAMS
diff --git a/plugins/Cardinal/src/glBars.cpp b/plugins/Cardinal/src/glBars.cpp
new file mode 100644
index 0000000..520f868
--- /dev/null
+++ b/plugins/Cardinal/src/glBars.cpp
@@ -0,0 +1,99 @@
+/*
+ * DISTRHO Cardinal Plugin
+ * Copyright (C) 2021 Filipe Coelho
+ *
+ * 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(Vec(0, 0)));
+ addChild(createWidget(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(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(Vec(3, 54), module, glBarsModule::IN1_INPUT));
+ }
+};
+
+Model* modelGlBars = createModel("glBars");
diff --git a/plugins/Cardinal/src/glBars.hpp b/plugins/Cardinal/src/glBars.hpp
new file mode 100644
index 0000000..28e1a57
--- /dev/null
+++ b/plugins/Cardinal/src/glBars.hpp
@@ -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
+ * Copyright (C) 2015 Nedko Arnaudov
+ * Copyright (C) 2016-2019 Filipe Coelho
+ *
+ * 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]= 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 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
diff --git a/plugins/Cardinal/src/plugin.hpp b/plugins/Cardinal/src/plugin.hpp
index 6709fbb..beb6970 100644
--- a/plugins/Cardinal/src/plugin.hpp
+++ b/plugins/Cardinal/src/plugin.hpp
@@ -23,5 +23,6 @@ using namespace rack;
extern Plugin* pluginInstance;
+extern Model* modelGlBars;
extern Model* modelHostParameters;
extern Model* modelHostTime;
diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp
index 116f54f..e3fbd0e 100644
--- a/plugins/plugins.cpp
+++ b/plugins/plugins.cpp
@@ -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);
}
diff --git a/src/CardinalUI.cpp b/src/CardinalUI.cpp
index 390c80b..2188942 100644
--- a/src/CardinalUI.cpp
+++ b/src/CardinalUI.cpp
@@ -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.