Browse Source

Add SliderKnob as SVGSlider's superclass. Add logarithmic scaling too ParamQuantity

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
6a83a3c766
10 changed files with 138 additions and 16 deletions
  1. +1
    -0
      include/app/Knob.hpp
  2. +2
    -2
      include/app/SVGSlider.hpp
  3. +19
    -0
      include/app/SliderKnob.hpp
  4. +5
    -1
      include/dsp/fft.hpp
  5. +0
    -3
      include/ui/Slider.hpp
  6. +9
    -2
      src/app/Knob.cpp
  7. +1
    -1
      src/app/ModuleWidget.cpp
  8. +16
    -6
      src/app/ParamQuantity.cpp
  9. +81
    -0
      src/dsp/minblep.cpp
  10. +4
    -1
      src/ui/Slider.cpp

+ 1
- 0
include/app/Knob.hpp View File

@@ -16,6 +16,7 @@ struct Knob : ParamWidget {
bool snap = false;
float snapValue = NAN;

void onHover(const event::Hover &e) override;
void onButton(const event::Button &e) override;
void onDragStart(const event::DragStart &e) override;
void onDragEnd(const event::DragEnd &e) override;


+ 2
- 2
include/app/SVGSlider.hpp View File

@@ -1,6 +1,6 @@
#pragma once
#include "app/common.hpp"
#include "app/Knob.hpp"
#include "app/SliderKnob.hpp"
#include "widgets/FramebufferWidget.hpp"
#include "widgets/SVGWidget.hpp"

@@ -11,7 +11,7 @@ namespace rack {
/** Behaves like a knob but linearly moves an SVGWidget between two points.
Can be used for horizontal or vertical linear faders.
*/
struct SVGSlider : Knob {
struct SVGSlider : SliderKnob {
FramebufferWidget *fb;
SVGWidget *background;
SVGWidget *handle;


+ 19
- 0
include/app/SliderKnob.hpp View File

@@ -0,0 +1,19 @@
#pragma once
#include "app/common.hpp"
#include "app/Knob.hpp"


namespace rack {


struct SliderKnob : Knob {
void onHover(const event::Hover &e) override {
ParamWidget::onHover(e);
}
void onButton(const event::Button &e) override {
ParamWidget::onButton(e);
}
};


} // namespace rack

+ 5
- 1
include/dsp/fft.hpp View File

@@ -19,7 +19,8 @@ void alignedDelete(T *p) {


/** Real-valued FFT context
Wraps PFFFT (https://bitbucket.org/jpommier/pffft/)
Wrapper for PFFFT (https://bitbucket.org/jpommier/pffft/)
`length` must be a multiple of 32.
*/
struct RealFFT {
PFFFT_Setup *setup;
@@ -83,6 +84,9 @@ struct RealFFT {
};


/** Complex-valued FFT context
`length` must be a multiple of 16.
*/
struct ComplexFFT {
PFFFT_Setup *setup;
int length;


+ 0
- 3
include/ui/Slider.hpp View File

@@ -8,9 +8,6 @@
namespace rack {


static const float SLIDER_SENSITIVITY = 0.001f;


struct Slider : OpaqueWidget {
BNDwidgetState state = BND_DEFAULT;
Quantity *quantity = NULL;


+ 9
- 2
src/app/Knob.cpp View File

@@ -10,11 +10,18 @@ namespace rack {
static const float KNOB_SENSITIVITY = 0.0015f;


void Knob::onHover(const event::Hover &e) {
math::Vec c = box.size.div(2);
float dist = e.pos.minus(c).norm();
if (dist <= c.x) {
ParamWidget::onHover(e);
}
}

void Knob::onButton(const event::Button &e) {
float r = box.size.x / 2;
math::Vec c = box.size.div(2);
float dist = e.pos.minus(c).norm();
if (dist <= r) {
if (dist <= c.x) {
ParamWidget::onButton(e);
}
}


+ 1
- 1
src/app/ModuleWidget.cpp View File

@@ -286,7 +286,7 @@ void ModuleWidget::draw(NVGcontext *vg) {
nvgRect(vg,
0, box.size.y - 20,
65, 20);
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.5));
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.75));
nvgFill(vg);

std::string cpuText = string::f("%.2f ÎĽs", module->cpuTime * 1e6f);


+ 16
- 6
src/app/ParamQuantity.cpp View File

@@ -58,34 +58,44 @@ float ParamQuantity::getDefaultValue() {
float ParamQuantity::getDisplayValue() {
if (!module)
return Quantity::getDisplayValue();
if (getParam()->displayBase == 0.f) {
float displayBase = getParam()->displayBase;
if (displayBase == 0.f) {
// Linear
return getSmoothValue() * getParam()->displayMultiplier;
}
else if (getParam()->displayBase == 1.f) {
else if (displayBase == 1.f) {
// Fixed (special case of exponential)
return getParam()->displayMultiplier;
}
else if (displayBase < 0.f) {
// Logarithmic
return std::log(getSmoothValue()) / std::log(-displayBase) * getParam()->displayMultiplier;
}
else {
// Exponential
return std::pow(getParam()->displayBase, getSmoothValue()) * getParam()->displayMultiplier;
return std::pow(displayBase, getSmoothValue()) * getParam()->displayMultiplier;
}
}

void ParamQuantity::setDisplayValue(float displayValue) {
if (!module)
return;
if (getParam()->displayBase == 0.f) {
float displayBase = getParam()->displayBase;
if (displayBase == 0.f) {
// Linear
setValue(displayValue / getParam()->displayMultiplier);
}
else if (getParam()->displayBase == 1.f) {
else if (displayBase == 1.f) {
// Fixed
setValue(getParam()->displayMultiplier);
}
else if (displayBase < 0.f) {
// Logarithmic
setValue(std::pow(displayBase, displayValue / getParam()->displayMultiplier));
}
else {
// Exponential
setValue(std::log(displayValue / getParam()->displayMultiplier) / std::log(getParam()->displayBase));
setValue(std::log(displayValue / getParam()->displayMultiplier) / std::log(displayBase));
}
}



+ 81
- 0
src/dsp/minblep.cpp View File

@@ -0,0 +1,81 @@
#include "dsp/minblep.hpp"
#include "dsp/fft.hpp"


namespace rack {
namespace dsp {


void minBlepImpulse(int z, int o, float *output) {
// Symmetric sinc array with `z` zero-crossings on each side
int n = 2 * z * o;
float *x = alignedNew<float>(n);
for (int i = 0; i < n; i++) {
float p = math::rescale((float) i, 0.f, (float) (n - 1), (float) -z, (float) z);
x[i] = sinc(p);
}

// Apply window
blackmanHarrisWindow(x, n);

// Real cepstrum
float *fx = alignedNew<float>(2*n);
RealFFT rfft(n);
rfft.rfft(x, fx);
// fx = log(abs(fx))
fx[0] = std::log(std::abs(fx[0]));
for (int i = 1; i < n; i++) {
fx[2*i] = std::log(std::hypot(fx[2*i], fx[2*i+1]));
fx[2*i+1] = 0.f;
}
fx[1] = std::log(std::abs(fx[1]));
// Clamp values in case we have -inf
for (int i = 0; i < 2*n; i++) {
fx[i] = std::max(-30.f, fx[i]);
}
rfft.irfft(fx, x);
rfft.scale(x);

// Minimum-phase reconstruction
for (int i = 1; i < n / 2; i++) {
x[i] *= 2.f;
}
for (int i = (n + 1) / 2; i < n; i++) {
x[i] = 0.f;
}
rfft.rfft(x, fx);
// fx = exp(fx)
fx[0] = std::exp(fx[0]);
for (int i = 1; i < n; i++) {
float re = std::exp(fx[2*i]);
float im = fx[2*i+1];
fx[2*i] = re * std::cos(im);
fx[2*i+1] = re * std::sin(im);
}
fx[1] = std::exp(fx[1]);
rfft.irfft(fx, x);
rfft.scale(x);

// Integrate
float total = 0.f;
for (int i = 0; i < n; i++) {
total += x[i];
x[i] = total;
}

// Normalize
float norm = 1.f / x[n - 1];
for (int i = 0; i < n; i++) {
x[i] *= norm;
}

std::memcpy(output, x, n * sizeof(float));

// Cleanup
alignedDelete(x);
alignedDelete(fx);
}


} // namespace dsp
} // namespace rack

+ 4
- 1
src/ui/Slider.cpp View File

@@ -4,6 +4,9 @@
namespace rack {


static const float SENSITIVITY = 0.001f;


Slider::Slider() {
box.size.y = BND_WIDGET_HEIGHT;
}
@@ -26,7 +29,7 @@ void Slider::onDragStart(const event::DragStart &e) {

void Slider::onDragMove(const event::DragMove &e) {
if (quantity) {
quantity->moveScaledValue(SLIDER_SENSITIVITY * e.mouseDelta.x);
quantity->moveScaledValue(SENSITIVITY * e.mouseDelta.x);
}
}



Loading…
Cancel
Save