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