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 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + 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.