From 18628c86abbb063baec517358e38ee6f3b5b6ba5 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 26 Jan 2017 05:45:00 -0500 Subject: [PATCH] Now requires SSE, added RadioButton, added hardcoded minBLEP, added CPU usage button --- Makefile | 2 +- README.md | 2 +- include/dsp.hpp | 79 ++++++++++- include/math.hpp | 103 ++++---------- include/rack.hpp | 2 +- include/rackwidgets.hpp | 224 +++++++++++++++++++++++++++++++ include/util.hpp | 1 - include/widgets.hpp | 223 ++----------------------------- src/Rack.cpp | 5 + src/dsp/minBLEP.cpp | 251 +---------------------------------- src/main.cpp | 4 +- src/widgets/Knob.cpp | 2 +- src/widgets/ModulePanel.cpp | 3 + src/widgets/ModuleWidget.cpp | 14 +- src/widgets/RadioButton.cpp | 28 ++++ src/widgets/Toolbar.cpp | 14 +- 16 files changed, 403 insertions(+), 554 deletions(-) create mode 100644 include/rackwidgets.hpp create mode 100644 src/widgets/RadioButton.cpp diff --git a/Makefile b/Makefile index 6026dbc0..cc86228e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ARCH ?= linux CFLAGS = -MMD -g -Wall -O2 -CXXFLAGS = -MMD -g -Wall -std=c++11 -O3 -ffast-math -fno-exceptions \ +CXXFLAGS = -MMD -g -Wall -std=c++11 -O3 -msse -mfpmath=sse -ffast-math -fno-exceptions \ -I./ext -I./include LDFLAGS = diff --git a/README.md b/README.md index 78fa32ec..5f3e0312 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ *Note: This software is in semi-public alpha. If you have stumbled upon this project, feel free to try it out and report bugs to the GitHub issue tracker. However, with more users it becomes difficult to make breaking changes, so please don't spread this to your friends and the Internet just yet, until the official announcement has been made.* -*Feel free to post **bugs**, **enhancements**, and **questions** on the [Issue Tracker](https://github.com/AndrewBelt/Rack/issues). To vote for a feature, give a thumbs-up on the first post.* +*Feel free to post bugs, enhancements, and questions on the [Issue Tracker](https://github.com/AndrewBelt/Rack/issues). To vote for a feature, give a thumbs-up on the first post.* # Rack diff --git a/include/dsp.hpp b/include/dsp.hpp index 8d1b7fa1..729a18c8 100644 --- a/include/dsp.hpp +++ b/include/dsp.hpp @@ -3,14 +3,78 @@ #include #include #include -#include "util.hpp" +#include +#include "math.hpp" -// in minBLEP.cpp -float *generateMinBLEP(int zeroCrossings, int overSampling); +namespace rack { -namespace rack { +/** Construct a C-style complex float +With -O3 this is as fast as the 1.0 + 1.0*I syntax but it stops the compiler from complaining +*/ +inline float _Complex complexf(float r, float i) { + union { + float x[2]; + float _Complex c; + } v; + v.x[0] = r; + v.x[1] = i; + return v.c; +} + +/** Simple FFT implementation +If you need something fast, use pffft, KissFFT, etc instead. +The size N must be a power of 2 +*/ +struct SimpleFFT { + int N; + /** Twiddle factors e^(2pi k/N), interleaved complex numbers */ + float _Complex *tw; + SimpleFFT(int N, bool inverse) : N(N) { + tw = new float _Complex[N]; + for (int i = 0; i < N; i++) { + float phase = 2*M_PI * (float)i / N; + if (inverse) + phase *= -1.0; + tw[i] = cexpf(phase * complexf(0.0, 1.0)); + } + } + ~SimpleFFT() { + delete[] tw; + } + /** Reference naive implementation + x and y are arrays of interleaved complex numbers + y must be size N/s + s is the stride factor for the x array which divides the size N + */ + void dft(const float _Complex *x, float _Complex *y, int s=1) { + for (int k = 0; k < N/s; k++) { + float _Complex yk = 0.0; + for (int n = 0; n < N; n += s) { + int m = (n*k) % N; + yk += x[n] * tw[m]; + } + y[k] = yk; + } + } + void fft(const float _Complex *x, float _Complex *y, int s=1) { + if (N/s <= 2) { + // Naive DFT is faster than further FFT recursions at this point + dft(x, y, s); + return; + } + float _Complex e[N/(2*s)]; // Even inputs + float _Complex o[N/(2*s)]; // Odd inputs + fft(x, e, 2*s); + fft(x + s, o, 2*s); + for (int k = 0; k < N/(2*s); k++) { + int m = (k*s) % N; + y[k] = e[k] + tw[m] * o[k]; + y[k + N/(2*s)] = e[k] - tw[m] * o[k]; + } + } +}; /** A simple cyclic buffer. @@ -196,12 +260,15 @@ struct SampleRateConverter { }; +// Pre-made minBLEP samples in minBLEP.cpp +extern const float minblep_16_32[]; + + template struct MinBLEP { float buf[2*ZERO_CROSSINGS] = {}; int pos = 0; - /** You must set this to the array generated by generateMinBLEP() */ - float *minblep = NULL; + const float *minblep; int oversample; /** Places a discontinuity with magnitude dx at -1 < p <= 0 relative to the current frame */ diff --git a/include/math.hpp b/include/math.hpp index 0eebba0a..0af62659 100644 --- a/include/math.hpp +++ b/include/math.hpp @@ -60,11 +60,11 @@ inline float quintic(float x) { return x*x*x*x*x; } -// Euclidean modulus, always returns 0 <= mod < base for positive base -// Assumes this architecture's division is non-Euclidean -inline int eucMod(int a, int base) { - int mod = a % base; - return mod < 0 ? mod + base : mod; +inline float sincf(float x) { + if (x == 0.0) + return 1.0; + x *= M_PI; + return sinf(x) / x; } inline float getf(const float *p, float v = 0.0) { @@ -85,6 +85,25 @@ inline float interpf(const float *p, float x) { return crossf(p[xi], p[xi+1], xf); } +// Euclidean modulus, always returns 0 <= mod < base for positive base +// Assumes this architecture's division is non-Euclidean +inline int eucmod(int a, int base) { + int mod = a % base; + return mod < 0 ? mod + base : mod; +} + +inline int log2i(int n) { + int i = 0; + while (n >>= 1) { + i++; + } + return i; +} + +inline bool ispow2(int n) { + return n > 0 && (n & (n - 1)) == 0; +} + //////////////////// // 2D float vector //////////////////// @@ -167,79 +186,5 @@ struct Rect { } }; -//////////////////// -// Simple FFT implementation -//////////////////// - -// Derived from the Italian Wikipedia article for FFT -// https://it.wikipedia.org/wiki/Trasformata_di_Fourier_veloce -// If you need speed, use KissFFT, pffft, etc instead. - -inline int log2i(int n) { - int i = 0; - while (n >>= 1) { - i++; - } - return i; -} - -inline bool isPowerOf2(int n) { - return n > 0 && (n & (n-1)) == 0; -} - -/* -inline int reverse(int N, int n) //calculating revers number -{ - int j, p = 0; - for(j = 1; j <= log2i(N); j++) { - if(n & (1 << (log2i(N) - j))) - p |= 1 << (j - 1); - } - return p; -} - -inline void ordina(complex* f1, int N) //using the reverse order in the array -{ - complex f2[MAX]; - for(int i = 0; i < N; i++) - f2[i] = f1[reverse(N, i)]; - for(int j = 0; j < N; j++) - f1[j] = f2[j]; -} - -inline void transform(complex* f, int N) -{ - ordina(f, N); //first: reverse order - complex *W; - W = (complex *)malloc(N / 2 * sizeof(complex)); - W[1] = polar(1., -2. * M_PI / N); - W[0] = 1; - for(int i = 2; i < N / 2; i++) - W[i] = pow(W[1], i); - int n = 1; - int a = N / 2; - for(int j = 0; j < log2i(N); j++) { - for(int i = 0; i < N; i++) { - if(!(i & n)) { - complex temp = f[i]; - complex Temp = W[(i * a) % (n * a)] * f[i + n]; - f[i] = temp + Temp; - f[i + n] = temp - Temp; - } - } - n *= 2; - a = a / 2; - } -} - -inline void FFT(complex* f, int N, double d) -{ - transform(f, N); - for(int i = 0; i < N; i++) - f[i] *= d; //multiplying by step -} -*/ - - } // namespace rack diff --git a/include/rack.hpp b/include/rack.hpp index d4171ea5..781c0a88 100644 --- a/include/rack.hpp +++ b/include/rack.hpp @@ -7,7 +7,7 @@ #include #include #include -#include "widgets.hpp" +#include "rackwidgets.hpp" namespace rack { diff --git a/include/rackwidgets.hpp b/include/rackwidgets.hpp new file mode 100644 index 00000000..c254338d --- /dev/null +++ b/include/rackwidgets.hpp @@ -0,0 +1,224 @@ +#pragma once + +#include "widgets.hpp" +#include + + +namespace rack { + + +struct Module; +struct Wire; + +struct RackWidget; +struct ParamWidget; +struct InputPort; +struct OutputPort; + + +//////////////////// +// module +//////////////////// + +// A 1U module should be 15x380. Thus the width of a module should be a factor of 15. +struct Model; +struct ModuleWidget : OpaqueWidget { + Model *model = NULL; + // Eventually this should be replaced with a `moduleId` which will be used for inter-process communication between the gui world and the audio world. + Module *module = NULL; + // int moduleId; + + std::vector inputs; + std::vector outputs; + std::vector params; + + ModuleWidget(Module *module); + ~ModuleWidget(); + // Convenience functions for adding special widgets (calls addChild()) + void addInput(InputPort *input); + void addOutput(OutputPort *output); + void addParam(ParamWidget *param); + + json_t *toJson(); + void fromJson(json_t *root); + void disconnectPorts(); + void resetParams(); + void cloneParams(ModuleWidget *source); + + void draw(NVGcontext *vg); + + bool requested = false; + Vec requestedPos; + Vec dragPos; + void onDragStart(); + void onDragMove(Vec mouseRel); + void onDragEnd(); + void onMouseDown(int button); +}; + +struct WireWidget : OpaqueWidget { + OutputPort *outputPort = NULL; + InputPort *inputPort = NULL; + Wire *wire = NULL; + NVGcolor color; + + WireWidget(); + ~WireWidget(); + void updateWire(); + void draw(NVGcontext *vg); + void drawOutputPlug(NVGcontext *vg); + void drawInputPlug(NVGcontext *vg); +}; + +struct RackWidget : OpaqueWidget { + // Only put ModuleWidgets in here + Widget *moduleContainer; + // Only put WireWidgets in here + Widget *wireContainer; + WireWidget *activeWire = NULL; + + RackWidget(); + ~RackWidget(); + void clear(); + void savePatch(std::string filename); + void loadPatch(std::string filename); + json_t *toJson(); + void fromJson(json_t *root); + + void repositionModule(ModuleWidget *module); + void step(); + void draw(NVGcontext *vg); + + void onMouseDown(int button); +}; + +struct ModulePanel : TransparentWidget { + NVGcolor backgroundColor; + NVGcolor highlightColor; + std::string imageFilename; + void draw(NVGcontext *vg); +}; + +//////////////////// +// params +//////////////////// + +struct Light : TransparentWidget, SpriteWidget { + NVGcolor color; + void draw(NVGcontext *vg); +}; + +// If you don't add these to your ModuleWidget, it will fall out of the RackWidget +struct Screw : TransparentWidget, SpriteWidget { + Screw(); +}; + +struct ParamWidget : OpaqueWidget, QuantityWidget { + Module *module = NULL; + int paramId; + + json_t *toJson(); + void fromJson(json_t *root); + void onMouseDown(int button); + void onChange(); +}; + +struct Knob : ParamWidget, SpriteWidget { + int minIndex, maxIndex, spriteCount; + void step(); + void onDragStart(); + void onDragMove(Vec mouseRel); + void onDragEnd(); +}; + +struct Switch : ParamWidget, SpriteWidget { +}; + +struct ToggleSwitch : virtual Switch { + void onDragStart() { + index = 1; + } + void onDragEnd() { + index = 0; + } + void onDragDrop(Widget *origin) { + if (origin != this) + return; + + // Cycle through modes + // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. + float v = value + 1.0; + setValue(v > maxValue ? minValue : v); + } +}; + +struct MomentarySwitch : virtual Switch { + void onDragStart() { + setValue(maxValue); + index = 1; + } + void onDragEnd() { + setValue(minValue); + index = 0; + } +}; + +//////////////////// +// ports +//////////////////// + +struct Port : OpaqueWidget, SpriteWidget { + Module *module = NULL; + WireWidget *connectedWire = NULL; + + Port(); + ~Port(); + void disconnect(); + + int type; + void drawGlow(NVGcontext *vg); + void onMouseDown(int button); + void onDragEnd(); +}; + +struct InputPort : Port { + int inputId; + + void draw(NVGcontext *vg); + void onDragStart(); + void onDragDrop(Widget *origin); +}; + +struct OutputPort : Port { + int outputId; + + void draw(NVGcontext *vg); + void onDragStart(); + void onDragDrop(Widget *origin); +}; + +//////////////////// +// scene +//////////////////// + +struct Toolbar : OpaqueWidget { + Slider *wireOpacitySlider; + Slider *wireTensionSlider; + RadioButton *cpuUsageButton; + + Toolbar(); + void draw(NVGcontext *vg); +}; + +struct Scene : OpaqueWidget { + Toolbar *toolbar; + ScrollWidget *scrollWidget; + Widget *overlay = NULL; + + Scene(); + void setOverlay(Widget *w); + void step(); +}; + + +} // namespace rack diff --git a/include/util.hpp b/include/util.hpp index 48071feb..7c6b423c 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -2,7 +2,6 @@ #include #include -#include "math.hpp" namespace rack { diff --git a/include/widgets.hpp b/include/widgets.hpp index b02b561f..b60c7d0d 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -6,23 +6,15 @@ #include #include -#include - #include "../ext/nanovg/src/nanovg.h" #include "../ext/oui/blendish.h" +#include "math.hpp" #include "util.hpp" namespace rack { -struct Module; -struct Wire; - -struct RackWidget; -struct ParamWidget; -struct InputPort; -struct OutputPort; //////////////////// // base class and traits @@ -227,6 +219,18 @@ struct ChoiceButton : Button { void draw(NVGcontext *vg); }; +struct RadioButton : OpaqueWidget, QuantityWidget { + BNDwidgetState state = BND_DEFAULT; + + RadioButton() { + box.size.y = BND_WIDGET_HEIGHT; + } + void draw(NVGcontext *vg); + void onMouseEnter(); + void onMouseLeave(); + void onDragDrop(Widget *origin); +}; + struct Slider : OpaqueWidget, QuantityWidget { BNDwidgetState state = BND_DEFAULT; @@ -272,206 +276,5 @@ struct Tooltip : Widget { void draw(NVGcontext *vg); }; -//////////////////// -// module -//////////////////// - -// A 1U module should be 15x380. Thus the width of a module should be a factor of 15. -struct Model; -struct ModuleWidget : OpaqueWidget { - Model *model = NULL; - // Eventually this should be replaced with a `moduleId` which will be used for inter-process communication between the gui world and the audio world. - Module *module = NULL; - // int moduleId; - - std::vector inputs; - std::vector outputs; - std::vector params; - - ModuleWidget(Module *module); - ~ModuleWidget(); - // Convenience functions for adding special widgets (calls addChild()) - void addInput(InputPort *input); - void addOutput(OutputPort *output); - void addParam(ParamWidget *param); - - json_t *toJson(); - void fromJson(json_t *root); - void disconnectPorts(); - void resetParams(); - void cloneParams(ModuleWidget *source); - - void draw(NVGcontext *vg); - - bool requested = false; - Vec requestedPos; - Vec dragPos; - void onDragStart(); - void onDragMove(Vec mouseRel); - void onDragEnd(); - void onMouseDown(int button); -}; - -struct WireWidget : OpaqueWidget { - OutputPort *outputPort = NULL; - InputPort *inputPort = NULL; - Wire *wire = NULL; - NVGcolor color; - - WireWidget(); - ~WireWidget(); - void updateWire(); - void draw(NVGcontext *vg); - void drawOutputPlug(NVGcontext *vg); - void drawInputPlug(NVGcontext *vg); -}; - -struct RackWidget : OpaqueWidget { - // Only put ModuleWidgets in here - Widget *moduleContainer; - // Only put WireWidgets in here - Widget *wireContainer; - WireWidget *activeWire = NULL; - - RackWidget(); - ~RackWidget(); - void clear(); - void savePatch(std::string filename); - void loadPatch(std::string filename); - json_t *toJson(); - void fromJson(json_t *root); - - void repositionModule(ModuleWidget *module); - void step(); - void draw(NVGcontext *vg); - - void onMouseDown(int button); -}; - -struct ModulePanel : TransparentWidget { - NVGcolor backgroundColor; - NVGcolor highlightColor; - std::string imageFilename; - void draw(NVGcontext *vg); -}; - -//////////////////// -// params -//////////////////// - -struct Light : TransparentWidget, SpriteWidget { - NVGcolor color; - void draw(NVGcontext *vg); -}; - -// If you don't add these to your ModuleWidget, it will fall out of the RackWidget -struct Screw : TransparentWidget, SpriteWidget { - Screw(); -}; - -struct ParamWidget : OpaqueWidget, QuantityWidget { - Module *module = NULL; - int paramId; - - json_t *toJson(); - void fromJson(json_t *root); - void onMouseDown(int button); - void onChange(); -}; - -struct Knob : ParamWidget, SpriteWidget { - int minIndex, maxIndex, spriteCount; - void step(); - void onDragStart(); - void onDragMove(Vec mouseRel); - void onDragEnd(); -}; - -struct Switch : ParamWidget, SpriteWidget { -}; - -struct ToggleSwitch : virtual Switch { - void onDragStart() { - index = 1; - } - void onDragEnd() { - index = 0; - } - void onDragDrop(Widget *origin) { - if (origin != this) - return; - - // Cycle through modes - // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. - float v = value + 1.0; - setValue(v > maxValue ? minValue : v); - } -}; - -struct MomentarySwitch : virtual Switch { - void onDragStart() { - setValue(maxValue); - index = 1; - } - void onDragEnd() { - setValue(minValue); - index = 0; - } -}; - -//////////////////// -// ports -//////////////////// - -struct Port : OpaqueWidget, SpriteWidget { - Module *module = NULL; - WireWidget *connectedWire = NULL; - - Port(); - ~Port(); - void disconnect(); - - int type; - void drawGlow(NVGcontext *vg); - void onMouseDown(int button); - void onDragEnd(); -}; - -struct InputPort : Port { - int inputId; - - void draw(NVGcontext *vg); - void onDragStart(); - void onDragDrop(Widget *origin); -}; - -struct OutputPort : Port { - int outputId; - - void draw(NVGcontext *vg); - void onDragStart(); - void onDragDrop(Widget *origin); -}; - -//////////////////// -// scene -//////////////////// - -struct Toolbar : OpaqueWidget { - Slider *wireOpacitySlider; - Slider *wireTensionSlider; - Toolbar(); - void draw(NVGcontext *vg); -}; - -struct Scene : OpaqueWidget { - Toolbar *toolbar; - ScrollWidget *scrollWidget; - Widget *overlay = NULL; - Scene(); - void setOverlay(Widget *w); - void step(); -}; - } // namespace rack diff --git a/src/Rack.cpp b/src/Rack.cpp index 9dd13838..c25acf9a 100644 --- a/src/Rack.cpp +++ b/src/Rack.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "rack.hpp" @@ -82,6 +83,10 @@ void Rack::stop() { } void Rack::run() { + // Set CPU to denormals-are-zero mode + // http://carlh.net/plugins/denormals.php + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + // Every time the rack waits and locks a mutex, it steps this many frames const int stepSize = 32; diff --git a/src/dsp/minBLEP.cpp b/src/dsp/minBLEP.cpp index 53fa9b76..a5f44def 100644 --- a/src/dsp/minBLEP.cpp +++ b/src/dsp/minBLEP.cpp @@ -1,251 +1,12 @@ - // MinBLEP Generation Code -// By Daniel Werner -// This Code Is Public Domain +#include "dsp.hpp" -#include -#define PI 3.14159265358979f +namespace rack { -// SINC Function -static float SINC(float x) -{ - float pix; - if(x == 0.0f) - return 1.0f; - else - { - pix = PI * x; - return sinf(pix) / pix; - } -} +const float minblep_16_32[] = { + 0.00011023, 0.00022416, 0.00034297, 0.00046661, 0.00059353, 0.00072403, 0.00085807, 0.00099544, 0.00113669, 0.00128244, 0.00143357, 0.00159180, 0.00175889, 0.00193681, 0.00212798, 0.00233618, 0.00256460, 0.00281804, 0.00310111, 0.00341981, 0.00378001, 0.00418855, 0.00465331, 0.00518249, 0.00578578, 0.00647247, 0.00725390, 0.00814134, 0.00914690, 0.01028436, 0.01156735, 0.01301055, 0.01462957, 0.01644073, 0.01846137, 0.02070885, 0.02320160, 0.02595890, 0.02900020, 0.03234551, 0.03601537, 0.04003051, 0.04441243, 0.04918219, 0.05436156, 0.05997159, 0.06603400, 0.07256979, 0.07960004, 0.08714473, 0.09522393, 0.10385663, 0.11306075, 0.12285375, 0.13325208, 0.14427035, 0.15592176, 0.16821821, 0.18117011, 0.19478568, 0.20907153, 0.22403158, 0.23966792, 0.25598019, 0.27296567, 0.29061884, 0.30893153, 0.32789305, 0.34748974, 0.36770493, 0.38851914, 0.40990984, 0.43185139, 0.45431516, 0.47726974, 0.50068015, 0.52450907, 0.54871643, 0.57325858, 0.59809023, 0.62316221, 0.64842403, 0.67382252, 0.69930243, 0.72480643, 0.75027585, 0.77565008, 0.80086774, 0.82586610, 0.85058230, 0.87495226, 0.89891225, 0.92239881, 0.94534874, 0.96769959, 0.98939002, 1.01036096, 1.03055346, 1.04991257, 1.06838441, 1.08591819, 1.10246634, 1.11798477, 1.13243258, 1.14577281, 1.15797329, 1.16900539, 1.17884552, 1.18747461, 1.19487906, 1.20105016, 1.20598388, 1.20968246, 1.21215260, 1.21340692, 1.21346366, 1.21234596, 1.21008229, 1.20670640, 1.20225751, 1.19677913, 1.19032025, 1.18293369, 1.17467666, 1.16561043, 1.15579987, 1.14531350, 1.13422263, 1.12260056, 1.11052382, 1.09806967, 1.08531761, 1.07234740, 1.05923963, 1.04607463, 1.03293216, 1.01989150, 1.00703001, 0.99442369, 0.98214602, 0.97026730, 0.95885533, 0.94797397, 0.93768352, 0.92803955, 0.91909295, 0.91089052, 0.90347338, 0.89687651, 0.89113057, 0.88625956, 0.88228178, 0.87920940, 0.87704903, 0.87580091, 0.87545884, 0.87601125, 0.87744081, 0.87972385, 0.88283205, 0.88673097, 0.89138156, 0.89674008, 0.90275854, 0.90938461, 0.91656262, 0.92423326, 0.93233514, 0.94080383, 0.94957352, 0.95857650, 0.96774524, 0.97700989, 0.98630202, 0.99555433, 1.00469887, 1.01367104, 1.02240634, 1.03084445, 1.03892660, 1.04659796, 1.05380774, 1.06050789, 1.06665611, 1.07221341, 1.07714641, 1.08142638, 1.08503044, 1.08793986, 1.09014225, 1.09163105, 1.09240448, 1.09246624, 1.09182608, 1.09049749, 1.08850145, 1.08586180, 1.08260751, 1.07877254, 1.07439494, 1.06951582, 1.06418049, 1.05843639, 1.05233502, 1.04592884, 1.03927267, 1.03242254, 1.02543569, 1.01836896, 1.01127994, 1.00422585, 0.99726236, 0.99044448, 0.98382431, 0.97745323, 0.97137886, 0.96564668, 0.96029860, 0.95537275, 0.95090336, 0.94692129, 0.94345307, 0.94051903, 0.93813735, 0.93632013, 0.93507481, 0.93440408, 0.93430620, 0.93477470, 0.93579876, 0.93736202, 0.93944514, 0.94202399, 0.94507092, 0.94855475, 0.95244062, 0.95669132, 0.96126628, 0.96612370, 0.97121888, 0.97650659, 0.98193920, 0.98746979, 0.99305087, 0.99863440, 1.00417352, 1.00962198, 1.01493454, 1.02006841, 1.02498233, 1.02963722, 1.03399694, 1.03802824, 1.04170084, 1.04498816, 1.04786694, 1.05031765, 1.05232465, 1.05387664, 1.05496621, 1.05558980, 1.05574775, 1.05544484, 1.05468917, 1.05349278, 1.05187225, 1.04984665, 1.04743862, 1.04467380, 1.04158032, 1.03818953, 1.03453457, 1.03065002, 1.02657270, 1.02234089, 1.01799285, 1.01356828, 1.00910676, 1.00464690, 1.00022852, 0.99588913, 0.99166596, 0.98759449, 0.98370826, 0.98003900, 0.97661632, 0.97346693, 0.97061497, 0.96808159, 0.96588528, 0.96404094, 0.96256018, 0.96145141, 0.96072024, 0.96036756, 0.96039182, 0.96078801, 0.96154761, 0.96265966, 0.96410930, 0.96587980, 0.96795046, 0.97029966, 0.97290313, 0.97573400, 0.97876412, 0.98196387, 0.98530257, 0.98874873, 0.99227041, 0.99583501, 0.99940956, 1.00296247, 1.00646222, 1.00987804, 1.01318014, 1.01634085, 1.01933396, 1.02213407, 1.02471924, 1.02706873, 1.02916455, 1.03099120, 1.03253567, 1.03378832, 1.03474081, 1.03538895, 1.03573155, 1.03576887, 1.03550470, 1.03494596, 1.03410137, 1.03298199, 1.03160226, 1.02997768, 1.02812684, 1.02606928, 1.02382588, 1.02142048, 1.01887643, 1.01621914, 1.01347411, 1.01066744, 1.00782573, 1.00497484, 1.00214148, 0.99935061, 0.99662775, 0.99399650, 0.99147928, 0.98909825, 0.98687279, 0.98482132, 0.98295969, 0.98130250, 0.97986293, 0.97865003, 0.97767186, 0.97693449, 0.97644144, 0.97619355, 0.97618985, 0.97642678, 0.97689945, 0.97759926, 0.97851688, 0.97964054, 0.98095751, 0.98245293, 0.98410982, 0.98591143, 0.98783875, 0.98987180, 0.99199086, 0.99417531, 0.99640393, 0.99865520, 1.00090814, 1.00314200, 1.00533652, 1.00747168, 1.00952899, 1.01149011, 1.01333869, 1.01505876, 1.01663721, 1.01806092, 1.01931858, 1.02040136, 1.02130210, 1.02201474, 1.02253604, 1.02286315, 1.02299595, 1.02293634, 1.02268875, 1.02225709, 1.02164853, 1.02087140, 1.01993537, 1.01885104, 1.01763213, 1.01629102, 1.01484251, 1.01330113, 1.01168346, 1.01000535, 1.00828362, 1.00653470, 1.00477552, 1.00302279, 1.00129271, 0.99960083, 0.99796313, 0.99639338, 0.99490535, 0.99351192, 0.99222440, 0.99105316, 0.99000835, 0.98909634, 0.98832458, 0.98769748, 0.98721880, 0.98689038, 0.98671335, 0.98668671, 0.98680866, 0.98707467, 0.98748106, 0.98802143, 0.98868805, 0.98947275, 0.99036646, 0.99135911, 0.99243897, 0.99359548, 0.99481559, 0.99608690, 0.99739677, 0.99873203, 1.00007975, 1.00142658, 1.00276041, 1.00406802, 1.00533855, 1.00655985, 1.00772119, 1.00881267, 1.00982487, 1.01075006, 1.01158035, 1.01230979, 1.01293266, 1.01344562, 1.01384568, 1.01412964, 1.01429844, 1.01435149, 1.01429081, 1.01411796, 1.01383793, 1.01345396, 1.01297212, 1.01239896, 1.01174057, 1.01100540, 1.01020169, 1.00933838, 1.00842452, 1.00746989, 1.00648463, 1.00547814, 1.00446069, 1.00344217, 1.00243223, 1.00143993, 1.00047517, 0.99954665, 0.99866235, 0.99782991, 0.99705631, 0.99634796, 0.99571103, 0.99514896, 0.99466711, 0.99426842, 0.99395454, 0.99372780, 0.99358785, 0.99353504, 0.99356812, 0.99368507, 0.99388355, 0.99415958, 0.99450946, 0.99492884, 0.99541146, 0.99595195, 0.99654400, 0.99718058, 0.99785507, 0.99856061, 0.99928933, 1.00003409, 1.00078654, 1.00154030, 1.00228751, 1.00302088, 1.00373411, 1.00442064, 1.00507402, 1.00568807, 1.00625861, 1.00678062, 1.00724947, 1.00766242, 1.00801611, 1.00830781, 1.00853622, 1.00870037, 1.00880003, 1.00883472, 1.00880599, 1.00871444, 1.00856256, 1.00835276, 1.00808787, 1.00777161, 1.00740683, 1.00699902, 1.00655174, 1.00606918, 1.00555754, 1.00502074, 1.00446463, 1.00389385, 1.00331378, 1.00272894, 1.00214446, 1.00156450, 1.00099480, 1.00043809, 0.99989861, 0.99938035, 0.99888563, 0.99841738, 0.99797773, 0.99756885, 0.99719167, 0.99684638, 0.99653435, 0.99625492, 0.99600822, 0.99579257, 0.99560666, 0.99544859, 0.99531645, 0.99520802, 0.99512035, 0.99504977, 0.99499327, 0.99494720, 0.99490863, 0.99487358, 0.99483842, 0.99479860, 0.99475139, 0.99469274, 0.99461985, 0.99452943, 0.99441826, 0.99428391, 0.99412394, 0.99393618, 0.99371916, 0.99347186, 0.99319351, 0.99288350, 0.99254173, 0.99216926, 0.99176681, 0.99133593, 0.99087846, 0.99039710, 0.98989451, 0.98937410, 0.98883879, 0.98829341, 0.98774183, 0.98718870, 0.98663867, 0.98609704, 0.98556888, 0.98505920, 0.98457366, 0.98411739, 0.98369551, 0.98331392, 0.98297703, 0.98268992, 0.98245704, 0.98228276, 0.98217118, 0.98212564, 0.98214996, 0.98224646, 0.98241693, 0.98266387, 0.98298812, 0.98339027, 0.98387039, 0.98442757, 0.98506147, 0.98577005, 0.98655069, 0.98740059, 0.98831660, 0.98929417, 0.99032903, 0.99141610, 0.99254966, 0.99372399, 0.99493235, 0.99616790, 0.99742448, 0.99869454, 0.99997079, 1.00124514, 1.00251019, 1.00375855, 1.00498211, 1.00617325, 1.00732577, 1.00843060, 1.00948179, 1.01047242, 1.01139629, 1.01224756, 1.01302052, 1.01371098, 1.01431394, 1.01482534, 1.01524329, 1.01556420, 1.01578641, 1.01590872, 1.01593041, 1.01585221, 1.01567483, 1.01539934, 1.01502872, 1.01456475, 1.01401234, 1.01337564, 1.01265824, 1.01186681, 1.01100624, 1.01008308, 1.00910449, 1.00807726, 1.00700867, 1.00590730, 1.00478077, 1.00363719, 1.00248516, 1.00133204, 1.00018704, 0.99905777, 0.99795246, 0.99687880, 0.99584419, 0.99485654, 0.99392235, 0.99304855, 0.99224019, 0.99150354, 0.99084306, 0.99026269, 0.98976678, 0.98935860, 0.98903960, 0.98881179, 0.98867643, 0.98863405, 0.98868364, 0.98882431, 0.98905468, 0.98937207, 0.98977262, 0.99025381, 0.99081081, 0.99143785, 0.99213088, 0.99288279, 0.99368858, 0.99454105, 0.99543440, 0.99635935, 0.99730903, 0.99827605, 0.99925363, 1.00023246, 1.00120509, 1.00216508, 1.00310433, 1.00401509, 1.00489199, 1.00572717, 1.00651467, 1.00724912, 1.00792384, 1.00853491, 1.00907779, 1.00954843, 1.00994480, 1.01026309, 1.01050198, 1.01066041, 1.01073647, 1.01073205, 1.01064730, 1.01048374, 1.01024330, 1.00992775, 1.00954151, 1.00908792, 1.00857103, 1.00799608, 1.00736785, 1.00669181, 1.00597465, 1.00522304, 1.00444114, 1.00363779, 1.00281966, 1.00199306, 1.00116563, 1.00034273, 0.99953192, 0.99873996, 0.99797446, 0.99724007, 0.99654233, 0.99588805, 0.99528110, 0.99472731, 0.99422991, 0.99379259, 0.99341941, 0.99311274, 0.99287349, 0.99270529, 0.99260652, 0.99257857, 0.99261945, 0.99273038, 0.99290955, 0.99315345, 0.99346066, 0.99382687, 0.99424839, 0.99472272, 0.99524361, 0.99580789, 0.99640882, 0.99704123, 0.99769914, 0.99837738, 0.99906975, 0.99976873, 1.00046957, 1.00116682, 1.00185359, 1.00252378, 1.00317132, 1.00379229, 1.00438106, 1.00493193, 1.00543988, 1.00590360, 1.00631797, 1.00667834, 1.00698411, 1.00723267, 1.00742185, 1.00755143, 1.00761986, 1.00762773, 1.00757504, 1.00746322, 1.00729394, 1.00706911, 1.00679159, 1.00646341, 1.00608873, 1.00567114, 1.00521481, 1.00472414, 1.00420344, 1.00365949, 1.00309455, 1.00251555, 1.00192726, 1.00133574, 1.00074565, 1.00016236, 0.99959171, 0.99903804, 0.99850535, 0.99799985, 0.99752414, 0.99708354, 0.99668151, 0.99632025, 0.99600381, 0.99573332, 0.99551266, 0.99534053, 0.99522054, 0.99515241, 0.99513555, 0.99517030, 0.99525541, 0.99538952, 0.99557215, 0.99579948, 0.99607027, 0.99638057, 0.99672699, 0.99710703, 0.99751633, 0.99795067, 0.99840581, 0.99887735, 0.99936110, 0.99985218, 1.00034654, 1.00083947, 1.00132573, 1.00180173, 1.00226319, 1.00270593, 1.00312614, 1.00351942, 1.00388277, 1.00421333, 1.00450921, 1.00476730, 1.00498581, 1.00516307, 1.00529838, 1.00539017, 1.00543821, 1.00544345, 1.00540483, 1.00532460, 1.00520289, 1.00504267, 1.00484514, 1.00461233, 1.00434721, 1.00405192, 1.00373054, 1.00338578, 1.00302088, 1.00264025, 1.00224662, 1.00184488, 1.00143826, 1.00103080, 1.00062573, 1.00022781, 0.99984139, 0.99946749, 0.99911129, 0.99877495, 0.99846184, 0.99817514, 0.99791592, 0.99768758, 0.99749118, 0.99732894, 0.99720013, 0.99710739, 0.99705017, 0.99702936, 0.99704379, 0.99709320, 0.99717599, 0.99729306, 0.99744141, 0.99761915, 0.99782479, 0.99805552, 0.99830848, 0.99858129, 0.99887139, 0.99917626, 0.99949169, 0.99981594, 1.00014460, 1.00047433, 1.00080299, 1.00112653, 1.00144279, 1.00174880, 1.00204086, 1.00231719, 1.00257576, 1.00281310, 1.00302708, 1.00321829, 1.00338340, 1.00352204, 1.00363243, 1.00371420, 1.00376749, 1.00379157, 1.00378597, 1.00375187, 1.00369036, 1.00360274, 1.00348926, 1.00335169, 1.00319159, 1.00301039, 1.00281143, 1.00259674, 1.00236738, 1.00212586, 1.00187516, 1.00161850, 1.00135744, 1.00109494, 1.00083435, 1.00057673, 1.00032485, 1.00008142, 0.99984884, 0.99962848, 0.99942255, 0.99923331, 0.99906200, 0.99890971, 0.99877805, 0.99866712, 0.99857920, 0.99851406, 0.99847245, 0.99845350, 0.99845672, 0.99848276, 0.99853104, 0.99859989, 0.99868929, 0.99879676, 0.99892145, 0.99906349, 0.99921906, 0.99938750, 0.99956673, 0.99975437, 0.99995005, 1.00015068, 1.00035346, 1.00055718, 1.00075948, 1.00095868, 1.00115299, 1.00134051, 1.00151980, 1.00168908, 1.00184536, 1.00198960, 1.00211966, 1.00223446, 1.00233328, 1.00241554, 1.00247967, 1.00252616, 1.00255466, 1.00256550, 1.00255883, 1.00253487, 1.00249410, 1.00243723, 1.00236428, 1.00227737, 1.00217772, 1.00206661, 1.00194490, 1.00181246, 1.00167227, 1.00152564, 1.00137448, 1.00121903, 1.00106311, 1.00090694, 1.00075161, 1.00059938, 1.00045121, 1.00030851, 1.00017321, 1.00004661, 0.99992871, 0.99982160, 0.99972528, 0.99964148, 0.99956852, 0.99950951, 0.99946433, 0.99943203, 0.99941361, 0.99940944, 0.99941790, 0.99943894, 0.99947232, 0.99951869, 0.99957561, 0.99964315, 0.99972034, 0.99980599, 0.99989998, 1.00000000 +}; -// Generate Blackman Window -static void BlackmanWindow(int n, float *w) -{ - int m = n - 1; - int i; - float f1, f2, fm; - fm = (float)m; - for(i = 0; i <= m; i++) - { - f1 = (2.0f * PI * (float)i) / fm; - f2 = 2.0f * f1; - w[i] = 0.42f - (0.5f * cosf(f1)) + (0.08f * cosf(f2)); - } -} - -// Discrete Fourier Transform -static void DFT(int n, float *realTime, float *imagTime, float *realFreq, float *imagFreq) -{ - int k, i; - float sr, si, p; - - for(k = 0; k < n; k++) - { - realFreq[k] = 0.0f; - imagFreq[k] = 0.0f; - } - - for(k = 0; k < n; k++) - for(i = 0; i < n; i++) - { - p = (2.0f * PI * (float)(k * i)) / n; - sr = cosf(p); - si = -sinf(p); - realFreq[k] += (realTime[i] * sr) - (imagTime[i] * si); - imagFreq[k] += (realTime[i] * si) + (imagTime[i] * sr); - } -} - -// Inverse Discrete Fourier Transform -static void InverseDFT(int n, float *realTime, float *imagTime, float *realFreq, float *imagFreq) -{ - int k, i; - float sr, si, p; - - for(k = 0; k < n; k++) - { - realTime[k] = 0.0f; - imagTime[k] = 0.0f; - } - - for(k = 0; k < n; k++) - { - for(i = 0; i < n; i++) - { - p = (2.0f * PI * (float)(k * i)) / n; - sr = cosf(p); - si = -sinf(p); - realTime[k] += (realFreq[i] * sr) + (imagFreq[i] * si); - imagTime[k] += (realFreq[i] * si) - (imagFreq[i] * sr); - } - realTime[k] /= n; - imagTime[k] /= n; - } -} - -// Complex Absolute Value -static float cabs(float x, float y) -{ - return sqrtf((x * x) + (y * y)); -} - -// Complex Exponential -static void cexp(float x, float y, float *zx, float *zy) -{ - float expx; - - expx = expf(x); - *zx = expx * cosf(y); - *zy = expx * sinf(y); -} - -// Compute Real Cepstrum Of Signal -static void RealCepstrum(int n, float *signal, float *realCepstrum) -{ - float *realTime, *imagTime, *realFreq, *imagFreq; - int i; - - realTime = new float[n]; - imagTime = new float[n]; - realFreq = new float[n]; - imagFreq = new float[n]; - - // Compose Complex FFT Input - - for(i = 0; i < n; i++) - { - realTime[i] = signal[i]; - imagTime[i] = 0.0f; - } - - // Perform DFT - - DFT(n, realTime, imagTime, realFreq, imagFreq); - - // Calculate Log Of Absolute Value - - for(i = 0; i < n; i++) - { - realFreq[i] = logf(cabs(realFreq[i], imagFreq[i])); - imagFreq[i] = 0.0f; - } - - // Perform Inverse FFT - - InverseDFT(n, realTime, imagTime, realFreq, imagFreq); - - // Output Real Part Of FFT - for(i = 0; i < n; i++) - realCepstrum[i] = realTime[i]; - - delete realTime; - delete imagTime; - delete realFreq; - delete imagFreq; -} - -// Compute Minimum Phase Reconstruction Of Signal -static void MinimumPhase(int n, float *realCepstrum, float *minimumPhase) -{ - int i, nd2; - float *realTime, *imagTime, *realFreq, *imagFreq; - - nd2 = n / 2; - realTime = new float[n]; - imagTime = new float[n]; - realFreq = new float[n]; - imagFreq = new float[n]; - - if((n % 2) == 1) - { - realTime[0] = realCepstrum[0]; - for(i = 1; i < nd2; i++) - realTime[i] = 2.0f * realCepstrum[i]; - for(i = nd2; i < n; i++) - realTime[i] = 0.0f; - } - else - { - realTime[0] = realCepstrum[0]; - for(i = 1; i < nd2; i++) - realTime[i] = 2.0f * realCepstrum[i]; - realTime[nd2] = realCepstrum[nd2]; - for(i = nd2 + 1; i < n; i++) - realTime[i] = 0.0f; - } - - for(i = 0; i < n; i++) - imagTime[i] = 0.0f; - - DFT(n, realTime, imagTime, realFreq, imagFreq); - - for(i = 0; i < n; i++) - cexp(realFreq[i], imagFreq[i], &realFreq[i], &imagFreq[i]); - - InverseDFT(n, realTime, imagTime, realFreq, imagFreq); - - for(i = 0; i < n; i++) - minimumPhase[i] = realTime[i]; - - delete realTime; - delete imagTime; - delete realFreq; - delete imagFreq; -} - -// Generate MinBLEP And Return It In An Array Of Floating Point Values -float *generateMinBLEP(int zeroCrossings, int overSampling) -{ - int i, n; - float r, a, b; - float *buffer1, *buffer2, *minBLEP; - - n = (zeroCrossings * 2 * overSampling) + 1; - - buffer1 = new float[n]; - buffer2 = new float[n]; - - // Generate Sinc - - a = (float)-zeroCrossings; - b = (float)zeroCrossings; - for(i = 0; i < n; i++) - { - r = ((float)i) / ((float)(n - 1)); - buffer1[i] = SINC(a + (r * (b - a))); - } - - // Window Sinc - - BlackmanWindow(n, buffer2); - for(i = 0; i < n; i++) - buffer1[i] *= buffer2[i]; - - // Minimum Phase Reconstruction - - RealCepstrum(n, buffer1, buffer2); - MinimumPhase(n, buffer2, buffer1); - - // Integrate Into MinBLEP - - minBLEP = new float[n]; - a = 0.0f; - for(i = 0; i < n; i++) - { - a += buffer1[i]; - minBLEP[i] = a; - } - - // Normalize - a = minBLEP[n - 1]; - a = 1.0f / a; - for(i = 0; i < n; i++) - minBLEP[i] *= a; - - delete buffer1; - delete buffer2; - return minBLEP; -} \ No newline at end of file +} // namespace rack diff --git a/src/main.cpp b/src/main.cpp index 800fed4d..9a0b1cb6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,8 +9,8 @@ namespace rack { -std::string gApplicationName = "Virtuoso Rack"; -std::string gApplicationVersion = "v0.0.0 alpha"; +std::string gApplicationName = "VCV Rack"; +std::string gApplicationVersion = "v0.1.0 alpha"; Rack *gRack; diff --git a/src/widgets/Knob.cpp b/src/widgets/Knob.cpp index d85299e5..178a8a5e 100644 --- a/src/widgets/Knob.cpp +++ b/src/widgets/Knob.cpp @@ -7,7 +7,7 @@ namespace rack { void Knob::step() { - index = eucMod((int) roundf(mapf(value, minValue, maxValue, minIndex, maxIndex)), spriteCount); + index = eucmod((int) roundf(mapf(value, minValue, maxValue, minIndex, maxIndex)), spriteCount); } void Knob::onDragStart() { diff --git a/src/widgets/ModulePanel.cpp b/src/widgets/ModulePanel.cpp index 7a4b0e60..9b98a322 100644 --- a/src/widgets/ModulePanel.cpp +++ b/src/widgets/ModulePanel.cpp @@ -7,12 +7,15 @@ void ModulePanel::draw(NVGcontext *vg) { nvgBeginPath(vg); nvgRect(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); NVGpaint paint; + // Background gradient Vec c = box.pos; float length = box.size.norm(); paint = nvgRadialGradient(vg, c.x, c.y, 0.0, length, highlightColor, backgroundColor); nvgFillPaint(vg, paint); + // nvgFillColor(vg, backgroundColor); nvgFill(vg); + // Background image if (!imageFilename.empty()) { int imageId = loadImage(imageFilename); diff --git a/src/widgets/ModuleWidget.cpp b/src/widgets/ModuleWidget.cpp index bb524c20..bfe1d2d6 100644 --- a/src/widgets/ModuleWidget.cpp +++ b/src/widgets/ModuleWidget.cpp @@ -100,19 +100,23 @@ void ModuleWidget::draw(NVGcontext *vg) { bndBevel(vg, box.pos.x, box.pos.y, box.size.x, box.size.y); // CPU usage text - if (true) { + if (gScene->toolbar->cpuUsageButton->value != 0.0) { float cpuTime = module ? module->cpuTime : 0.0; std::string text = stringf("%.1f%%", cpuTime * 100.0); + nvgSave(vg); + nvgBeginPath(vg); + nvgRect(vg, box.pos.x, box.pos.y, box.size.x, BND_WIDGET_HEIGHT); + nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0)); + nvgFill(vg); nvgBeginPath(vg); cpuTime = clampf(cpuTime, 0.0, 1.0); - const float barWidth = 15.0; - nvgRect(vg, box.pos.x, box.pos.y + (1.0 - cpuTime) * box.size.y, barWidth, cpuTime * box.size.y); - nvgFillColor(vg, nvgHSLA(0.33 * cubic(1.0 - cpuTime), 1.0, 0.5, 128)); + nvgRect(vg, box.pos.x, box.pos.y, box.size.x * cpuTime, BND_WIDGET_HEIGHT); + nvgFillColor(vg, nvgHSL(0.33 * cubic(1.0 - cpuTime), 1.0, 0.4)); nvgFill(vg); - bndLabel(vg, box.pos.x, box.pos.y + box.size.y - BND_WIDGET_HEIGHT, box.size.x, BND_WIDGET_HEIGHT, -1, text.c_str()); + bndMenuItem(vg, box.pos.x, box.pos.y, box.size.x, BND_WIDGET_HEIGHT, BND_DEFAULT, -1, text.c_str()); nvgRestore(vg); } } diff --git a/src/widgets/RadioButton.cpp b/src/widgets/RadioButton.cpp new file mode 100644 index 00000000..02a5105c --- /dev/null +++ b/src/widgets/RadioButton.cpp @@ -0,0 +1,28 @@ +#include "rack.hpp" + + +namespace rack { + +void RadioButton::draw(NVGcontext *vg) { + bndRadioButton(vg, box.pos.x, box.pos.y, box.size.x, box.size.y, BND_CORNER_NONE, value == 0.0 ? state : BND_ACTIVE, -1, label.c_str()); +} + +void RadioButton::onMouseEnter() { + state = BND_HOVER; +} + +void RadioButton::onMouseLeave() { + state = BND_DEFAULT; +} + +void RadioButton::onDragDrop(Widget *origin) { + if (origin == this) { + if (value == 0.0) + value = 1.0; + else + value = 0.0; + } +} + + +} // namespace rack diff --git a/src/widgets/Toolbar.cpp b/src/widgets/Toolbar.cpp index bbf83612..f8ad8688 100644 --- a/src/widgets/Toolbar.cpp +++ b/src/widgets/Toolbar.cpp @@ -98,9 +98,9 @@ Toolbar::Toolbar() { { Label *label = new Label(); label->box.pos = Vec(xPos, margin); - label->text = gApplicationName + " " + gApplicationVersion; + label->text = gApplicationVersion; addChild(label); - xPos += 175; + xPos += 100; } xPos += margin; @@ -150,6 +150,16 @@ Toolbar::Toolbar() { addChild(wireTensionSlider); xPos += wireTensionSlider->box.size.x; } + + xPos += margin; + { + cpuUsageButton = new RadioButton(); + cpuUsageButton->box.pos = Vec(xPos, margin); + cpuUsageButton->box.size.x = 100; + cpuUsageButton->label = "CPU usage"; + addChild(cpuUsageButton); + xPos += cpuUsageButton->box.size.x; + } } void Toolbar::draw(NVGcontext *vg) {