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