@@ -4,3 +4,6 @@ | |||||
[submodule "ext/nanosvg"] | [submodule "ext/nanosvg"] | ||||
path = ext/nanosvg | path = ext/nanosvg | ||||
url = https://github.com/memononen/nanosvg.git | url = https://github.com/memononen/nanosvg.git | ||||
[submodule "ext/dr_libs"] | |||||
path = ext/dr_libs | |||||
url = https://github.com/mackron/dr_libs.git |
@@ -4,7 +4,7 @@ | |||||
# Rack | # Rack | ||||
Open source Eurorack-style modular DAW | |||||
Open source virtual Eurorack DAW | |||||
## Building | ## Building | ||||
@@ -21,3 +21,9 @@ Install dependencies | |||||
Run `make ARCH=lin` or `make ARCH=win` or `make ARCH=mac` | Run `make ARCH=lin` or `make ARCH=win` or `make ARCH=mac` | ||||
If the build breaks because you think I've missed a step, feel free to post an issue. | If the build breaks because you think I've missed a step, feel free to post an issue. | ||||
## License | |||||
Rack source code by Andrew Belt: BSD-3-Clause | |||||
Component Library graphics by [Grayscale](http://grayscale.info/): [CC BY-NC 4.0](https://creativecommons.org/licenses/by-nc/4.0/) |
@@ -0,0 +1 @@ | |||||
Subproject commit 6fb1f8a9f8bb3198e05ee52aa38f177c499c1bef |
@@ -440,8 +440,8 @@ struct SilverScrew : Screw { | |||||
struct LightPanel : Panel { | struct LightPanel : Panel { | ||||
LightPanel() { | LightPanel() { | ||||
backgroundColor = nvgRGB(0xe8, 0xe8, 0xe8); | |||||
borderColor = nvgRGB(0xa1, 0xa1, 0xa1); | |||||
backgroundColor = nvgRGB(0xf2, 0xf2, 0xf2); | |||||
borderColor = nvgRGB(0xb8, 0xb8, 0xb8); | |||||
} | } | ||||
}; | }; | ||||
@@ -5,6 +5,7 @@ | |||||
#include <samplerate.h> | #include <samplerate.h> | ||||
#include <complex> | #include <complex> | ||||
#include "math.hpp" | #include "math.hpp" | ||||
#include "../ext/dr_libs/dr_wav.h" | |||||
namespace rack { | namespace rack { | ||||
@@ -320,4 +321,23 @@ struct RCFilter { | |||||
}; | }; | ||||
struct PeakFilter { | |||||
float state = 0.0; | |||||
float c = 0.0; | |||||
/** Rate is lambda / sampleRate */ | |||||
void setRate(float r) { | |||||
c = 1.0 - r; | |||||
} | |||||
void process(float x) { | |||||
if (x > state) | |||||
state = x; | |||||
state *= c; | |||||
} | |||||
float peak() { | |||||
return state; | |||||
} | |||||
}; | |||||
} // namespace rack | } // namespace rack |
@@ -8,6 +8,7 @@ namespace rack { | |||||
void guiInit(); | void guiInit(); | ||||
void guiDestroy(); | void guiDestroy(); | ||||
void guiRun(); | void guiRun(); | ||||
bool guiIsKeyPressed(int key); | |||||
void guiCursorLock(); | void guiCursorLock(); | ||||
void guiCursorUnlock(); | void guiCursorUnlock(); | ||||
const char *guiSaveDialog(const char *filters, const char *filename); | const char *guiSaveDialog(const char *filters, const char *filename); | ||||
@@ -44,6 +44,11 @@ inline bool ispow2(int n) { | |||||
// float functions | // float functions | ||||
//////////////////// | //////////////////// | ||||
/** Returns 1.0 for positive numbers and -1.0 for negative numbers (including positive/negative zero) */ | |||||
inline float sgnf(float x) { | |||||
return copysignf(1.0, x); | |||||
} | |||||
inline float radtodeg(float x) { | inline float radtodeg(float x) { | ||||
return x * (180.0 / M_PI); | return x * (180.0 / M_PI); | ||||
} | } | ||||
@@ -191,6 +191,10 @@ Events are not passed to the underlying scene. | |||||
struct FramebufferWidget : virtual Widget { | struct FramebufferWidget : virtual Widget { | ||||
/** Set this to true to re-render the scene to the framebuffer in the next step() */ | /** Set this to true to re-render the scene to the framebuffer in the next step() */ | ||||
bool dirty = true; | bool dirty = true; | ||||
/** A margin in pixels around the scene in the framebuffer | |||||
This prevents cutting the rendered SVG off on the box edges. | |||||
*/ | |||||
int margin = 0; | |||||
/** The root object in the framebuffer scene | /** The root object in the framebuffer scene | ||||
The FramebufferWidget owns the pointer | The FramebufferWidget owns the pointer | ||||
*/ | */ | ||||
@@ -4,7 +4,7 @@ | |||||
namespace rack { | namespace rack { | ||||
std::string gApplicationName = "VCV Rack"; | std::string gApplicationName = "VCV Rack"; | ||||
std::string gApplicationVersion = "v0.1.1 alpha"; | |||||
std::string gApplicationVersion = "v0.2.0 alpha"; | |||||
RackWidget *gRackWidget = NULL; | RackWidget *gRackWidget = NULL; | ||||
@@ -1,5 +1,7 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "gui.hpp" | #include "gui.hpp" | ||||
// For GLFW_KEY_LEFT_CONTROL, etc. | |||||
#include <GLFW/glfw3.h> | |||||
namespace rack { | namespace rack { | ||||
@@ -12,6 +14,9 @@ void Knob::onDragStart() { | |||||
} | } | ||||
void Knob::onDragMove(Vec mouseRel) { | void Knob::onDragMove(Vec mouseRel) { | ||||
// Drag slower if Ctrl is held | |||||
if (guiIsKeyPressed(GLFW_KEY_LEFT_CONTROL) || guiIsKeyPressed(GLFW_KEY_RIGHT_CONTROL)) | |||||
mouseRel = mouseRel.mult(0.1); | |||||
setValue(value - KNOB_SENSITIVITY * (maxValue - minValue) * mouseRel.y); | setValue(value - KNOB_SENSITIVITY * (maxValue - minValue) * mouseRel.y); | ||||
} | } | ||||
@@ -5,6 +5,8 @@ namespace rack { | |||||
SVGKnob::SVGKnob() { | SVGKnob::SVGKnob() { | ||||
margin = 1; | |||||
tw = new TransformWidget(); | tw = new TransformWidget(); | ||||
setScene(tw); | setScene(tw); | ||||
@@ -44,7 +46,7 @@ void SVGKnob::draw(NVGcontext *vg) { | |||||
nvgRect(vg, -margin, -margin, box.size.x + 2*margin, box.size.y + 2*margin); | nvgRect(vg, -margin, -margin, box.size.x + 2*margin, box.size.y + 2*margin); | ||||
nvgFillColor(vg, nvgRGBAf(0.0, 0.0, 0.0, 0.25)); | nvgFillColor(vg, nvgRGBAf(0.0, 0.0, 0.0, 0.25)); | ||||
Vec c = box.size.div(2.0); | Vec c = box.size.div(2.0); | ||||
float radius = c.x - 1; | |||||
float radius = c.x; | |||||
NVGcolor icol = nvgRGBAf(0.0, 0.0, 0.0, 0.25); | NVGcolor icol = nvgRGBAf(0.0, 0.0, 0.0, 0.25); | ||||
NVGcolor ocol = nvgRGBAf(0.0, 0.0, 0.0, 0.0); | NVGcolor ocol = nvgRGBAf(0.0, 0.0, 0.0, 0.0); | ||||
NVGpaint paint = nvgRadialGradient(vg, c.x, c.y + 1, radius, radius + 3, icol, ocol); | NVGpaint paint = nvgRadialGradient(vg, c.x, c.y + 1, radius, radius + 3, icol, ocol); | ||||
@@ -1,6 +1,10 @@ | |||||
#include "dsp.hpp" | #include "dsp.hpp" | ||||
#define DR_WAV_IMPLEMENTATION | |||||
#include "../ext/dr_libs/dr_wav.h" | |||||
namespace rack { | namespace rack { | ||||
@@ -79,19 +79,11 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||||
Vec mouseRel = mousePos.minus(gMousePos); | Vec mouseRel = mousePos.minus(gMousePos); | ||||
gMousePos = mousePos; | gMousePos = mousePos; | ||||
bool locked = glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; | |||||
// onMouseMove | // onMouseMove | ||||
Widget *hovered = gScene->onMouseMove(gMousePos, mouseRel); | Widget *hovered = gScene->onMouseMove(gMousePos, mouseRel); | ||||
if (gDraggedWidget) { | if (gDraggedWidget) { | ||||
// onDragMove | // onDragMove | ||||
// Drag slower if Ctrl is held | |||||
if (locked) { | |||||
bool ctrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; | |||||
if (ctrl) | |||||
mouseRel = mouseRel.mult(0.1); | |||||
} | |||||
gDraggedWidget->onDragMove(mouseRel); | gDraggedWidget->onDragMove(mouseRel); | ||||
if (hovered != gDragHoveredWidget) { | if (hovered != gDragHoveredWidget) { | ||||
@@ -272,6 +264,10 @@ void guiRun() { | |||||
} | } | ||||
} | } | ||||
bool guiIsKeyPressed(int key) { | |||||
return glfwGetKey(window, key) == GLFW_PRESS; | |||||
} | |||||
void guiCursorLock() { | void guiCursorLock() { | ||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | ||||
} | } | ||||
@@ -32,11 +32,6 @@ FramebufferWidget::~FramebufferWidget() { | |||||
delete internal; | delete internal; | ||||
} | } | ||||
/** A margin in pixels around the scene in the framebuffer | |||||
This prevents cutting the rendered SVG off on the box edges. | |||||
*/ | |||||
static const int margin = 1; | |||||
void FramebufferWidget::step() { | void FramebufferWidget::step() { | ||||
if (!scene) | if (!scene) | ||||
return; | return; | ||||