| @@ -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. | ||||