/* * DISTRHO Cardinal Plugin * Copyright (C) 2021-2022 Filipe Coelho * * 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. */ /** * This file contains a substantial amount of code from VCVRack, adjusted for inline use * Copyright (C) 2016-2021 VCV. * * 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 (at your option) any later version. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #define assert(x) #define ENUMS(name, count) name, name ## _LAST = name + (count) - 1 #define VEC_ARGS(v) (v).x, (v).y #define RECT_ARGS(r) (r).pos.x, (r).pos.y, (r).size.x, (r).size.y #define GLFW_MOUSE_BUTTON_LEFT 0 #define GLFW_MOUSE_BUTTON_RIGHT 0 enum NVGalign { NVG_ALIGN_LEFT, NVG_ALIGN_RIGHT }; struct NVGcolor { float a; }; struct NVGpaint {}; struct NVGcontext {}; struct NSVGimage {}; inline NVGcolor nvgRGB(int r, int g, int b) { return {}; } inline NVGcolor nvgRGBA(int r, int g, int b, int a) { return {}; } inline NVGcolor nvgRGBf(float r, float g, float b) { return {}; } inline NVGcolor nvgRGBAf(float r, float g, float b, float a) { return {}; } inline NVGcolor nvgTransRGBA(NVGcolor, int) { return {}; } inline NVGcolor nvgTransRGBAf(NVGcolor, float) { return {}; } inline void nvgBeginPath(NVGcontext* vg) {} inline void nvgFillColor(NVGcontext* vg, NVGcolor) {} inline void nvgFillPaint(NVGcontext* vg, NVGpaint) {} inline void nvgFill(NVGcontext* vg) {} inline void nvgStrokeColor(NVGcontext* vg, NVGcolor) {} inline void nvgStrokeWidth(NVGcontext* vg, float) {} inline void nvgStroke(NVGcontext* vg) {} inline void nvgRect(NVGcontext* vg, float a, float b, float c, float d) {} inline void nvgImageSize(NVGcontext*, int, void*, void*) {} inline NVGpaint nvgImagePattern(NVGcontext*, float, float, float, float, float, int handle, float) { return {}; } inline void nvgRoundedRect(NVGcontext* vg, float, float, float, float, float) {} inline void nvgFontSize(NVGcontext*, int) {} inline void nvgFontFaceId(NVGcontext*, int) {} inline void nvgTextLetterSpacing(NVGcontext*, float) {} inline void nvgText(NVGcontext*, float, float, const char*, const char*) {} inline void nvgTextAlign(NVGcontext*, NVGalign) {} inline void nvgSave(NVGcontext*) {} inline void nvgRestore(NVGcontext*) {} inline void nvgScale(NVGcontext*, float, float) {} struct json_t {}; inline json_t* json_boolean(bool) { return NULL; } inline json_t* json_integer(int) { return NULL; } inline json_t* json_object(void) { return NULL; } inline json_t* json_object_get(json_t*, const char*) { return NULL; } inline bool json_is_true(json_t*) { return false; } inline bool json_boolean_value(json_t*) { return false; } inline int json_integer_value(json_t*) { return 0; } inline float json_number_value(json_t*) { return 0.f; } inline void json_object_set_new(json_t*, const char*, json_t*) {} inline json_t* json_array(void) { return NULL; } inline json_t* json_array_get(json_t*, int) { return NULL; } inline void json_array_insert_new(json_t*, int, json_t*) {} namespace rack { struct Quantity { virtual ~Quantity() {} virtual void setValue(float value) {} virtual float getValue() { return 0.f; } virtual float getMinValue() { return 0.f; } virtual float getMaxValue() { return 1.f; } virtual float getDefaultValue() { return 0.f; } // virtual float getDisplayValue(); // virtual void setDisplayValue(float displayValue); // virtual int getDisplayPrecision(); // virtual std::string getDisplayValueString(); // virtual void setDisplayValueString(std::string s); virtual std::string getLabel() { return ""; } virtual std::string getUnit() { return ""; } // virtual std::string getString(); // virtual void reset(); // virtual void randomize(); // bool isMin(); // bool isMax(); // void setMin(); // void setMax(); // void toggle(); // void moveValue(float deltaValue); // float getRange(); // bool isBounded(); // float toScaled(float value); // float fromScaled(float scaledValue); // void setScaledValue(float scaledValue); // float getScaledValue(); // void moveScaledValue(float deltaScaledValue); }; namespace ui { struct Menu; } namespace window { struct Svg; } namespace math { template inline bool isEven(T x) { return x % 2 == 0; } template inline bool isOdd(T x) { return x % 2 != 0; } inline int clamp(int x, int a, int b) { return std::max(std::min(x, b), a); } inline int clampSafe(int x, int a, int b) { return (a <= b) ? clamp(x, a, b) : clamp(x, b, a); } inline float clamp(float x, float a = 0.f, float b = 1.f) { return std::fmax(std::fmin(x, b), a); } inline float clampSafe(float x, float a = 0.f, float b = 1.f) { return (a <= b) ? clamp(x, a, b) : clamp(x, b, a); } inline int eucMod(int a, int b) { int mod = a % b; if (mod < 0) { mod += b; } return mod; } inline int eucDiv(int a, int b) { int div = a / b; int mod = a % b; if (mod < 0) { div -= 1; } return div; } inline void eucDivMod(int a, int b, int* div, int* mod) { *div = a / b; *mod = a % b; if (*mod < 0) { *div -= 1; *mod += b; } } inline int log2(int n) { int i = 0; while (n >>= 1) { i++; } return i; } template bool isPow2(T n) { return n > 0 && (n & (n - 1)) == 0; } template T sgn(T x) { return x > 0 ? 1 : (x < 0 ? -1 : 0); } #if defined __clang__ __attribute__((optnone)) #else __attribute__((optimize("signed-zeros"))) #endif inline float normalizeZero(float x) { return x + 0.f; } inline float eucMod(float a, float b) { float mod = std::fmod(a, b); if (mod < 0.f) { mod += b; } return mod; } inline bool isNear(float a, float b, float epsilon = 1e-6f) { return std::fabs(a - b) <= epsilon; } inline float chop(float x, float epsilon = 1e-6f) { return std::fabs(x) <= epsilon ? 0.f : x; } inline float rescale(float x, float xMin, float xMax, float yMin, float yMax) { return yMin + (x - xMin) / (xMax - xMin) * (yMax - yMin); } inline float crossfade(float a, float b, float p) { return a + (b - a) * p; } inline float interpolateLinear(const float* p, float x) { const int xi = x; const float xf = x - xi; return crossfade(p[xi], p[xi + 1], xf); } inline void complexMult(float ar, float ai, float br, float bi, float* cr, float* ci) { *cr = ar * br - ai * bi; *ci = ar * bi + ai * br; } struct Rect; struct Vec { float x = 0.f; float y = 0.f; Vec() {} Vec(float xy) : x(xy), y(xy) {} Vec(float x, float y) : x(x), y(y) {} float& operator[](int i) { return (i == 0) ? x : y; } const float& operator[](int i) const { return (i == 0) ? x : y; } Vec neg() const { return Vec(-x, -y); } Vec plus(Vec b) const { return Vec(x + b.x, y + b.y); } Vec minus(Vec b) const { return Vec(x - b.x, y - b.y); } Vec mult(float s) const { return Vec(x * s, y * s); } Vec mult(Vec b) const { return Vec(x * b.x, y * b.y); } Vec div(float s) const { return Vec(x / s, y / s); } Vec div(Vec b) const { return Vec(x / b.x, y / b.y); } float dot(Vec b) const { return x * b.x + y * b.y; } float arg() const { return std::atan2(y, x); } float norm() const { return std::hypot(x, y); } Vec normalize() const { return div(norm()); } float square() const { return x * x + y * y; } float area() const { return x * y; } Vec rotate(float angle) { float sin = std::sin(angle); float cos = std::cos(angle); return Vec(x * cos - y * sin, x * sin + y * cos); } Vec flip() const { return Vec(y, x); } Vec min(Vec b) const { return Vec(std::fmin(x, b.x), std::fmin(y, b.y)); } Vec max(Vec b) const { return Vec(std::fmax(x, b.x), std::fmax(y, b.y)); } Vec abs() const { return Vec(std::fabs(x), std::fabs(y)); } Vec round() const { return Vec(std::round(x), std::round(y)); } Vec floor() const { return Vec(std::floor(x), std::floor(y)); } Vec ceil() const { return Vec(std::ceil(x), std::ceil(y)); } bool equals(Vec b) const { return x == b.x && y == b.y; } bool isZero() const { return x == 0.f && y == 0.f; } bool isFinite() const { return std::isfinite(x) && std::isfinite(y); } Vec clamp(Rect bound) const; Vec clampSafe(Rect bound) const; Vec crossfade(Vec b, float p) { return this->plus(b.minus(*this).mult(p)); } bool isEqual(Vec b) const { return equals(b); } }; struct Rect { Vec pos; Vec size; Rect() {} Rect(Vec pos, Vec size) : pos(pos), size(size) {} Rect(float posX, float posY, float sizeX, float sizeY) : pos(Vec(posX, posY)), size(Vec(sizeX, sizeY)) {} static Rect fromMinMax(Vec a, Vec b) { return Rect(a, b.minus(a)); } static Rect fromCorners(Vec a, Vec b) { return fromMinMax(a.min(b), a.max(b)); } static Rect inf() { return Rect(Vec(-INFINITY, -INFINITY), Vec(INFINITY, INFINITY)); } bool contains(Vec v) const { return (pos.x <= v.x) && (size.x == INFINITY || v.x < pos.x + size.x) && (pos.y <= v.y) && (size.y == INFINITY || v.y < pos.y + size.y); } bool contains(Rect r) const { return (pos.x <= r.pos.x) && (r.pos.x - size.x <= pos.x - r.size.x) && (pos.y <= r.pos.y) && (r.pos.y - size.y <= pos.y - r.size.y); } bool intersects(Rect r) const { return (r.size.x == INFINITY || pos.x < r.pos.x + r.size.x) && (size.x == INFINITY || r.pos.x < pos.x + size.x) && (r.size.y == INFINITY || pos.y < r.pos.y + r.size.y) && (size.y == INFINITY || r.pos.y < pos.y + size.y); } bool equals(Rect r) const { return pos.equals(r.pos) && size.equals(r.size); } float getLeft() const { return pos.x; } float getRight() const { return (size.x == INFINITY) ? INFINITY : (pos.x + size.x); } float getTop() const { return pos.y; } float getBottom() const { return (size.y == INFINITY) ? INFINITY : (pos.y + size.y); } float getWidth() const { return size.x; } float getHeight() const { return size.y; } Vec getCenter() const { return pos.plus(size.mult(0.5f)); } Vec getTopLeft() const { return pos; } Vec getTopRight() const { return Vec(getRight(), getTop()); } Vec getBottomLeft() const { return Vec(getLeft(), getBottom()); } Vec getBottomRight() const { return Vec(getRight(), getBottom()); } Rect clamp(Rect bound) const { Rect r; r.pos.x = math::clampSafe(pos.x, bound.pos.x, bound.pos.x + bound.size.x); r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y); r.size.x = math::clamp(pos.x + size.x, bound.pos.x, bound.pos.x + bound.size.x) - r.pos.x; r.size.y = math::clamp(pos.y + size.y, bound.pos.y, bound.pos.y + bound.size.y) - r.pos.y; return r; } Rect nudge(Rect bound) const { Rect r; r.size = size; r.pos.x = math::clampSafe(pos.x, bound.pos.x, bound.pos.x + bound.size.x - size.x); r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y - size.y); return r; } Rect expand(Rect b) const { Rect r; r.pos.x = std::fmin(pos.x, b.pos.x); r.pos.y = std::fmin(pos.y, b.pos.y); r.size.x = std::fmax(pos.x + size.x, b.pos.x + b.size.x) - r.pos.x; r.size.y = std::fmax(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y; return r; } Rect intersect(Rect b) const { Rect r; r.pos.x = std::fmax(pos.x, b.pos.x); r.pos.y = std::fmax(pos.y, b.pos.y); r.size.x = std::fmin(pos.x + size.x, b.pos.x + b.size.x) - r.pos.x; r.size.y = std::fmin(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y; return r; } Rect zeroPos() const { return Rect(Vec(), size); } Rect grow(Vec delta) const { Rect r; r.pos = pos.minus(delta); r.size = size.plus(delta.mult(2.f)); return r; } Rect shrink(Vec delta) const { Rect r; r.pos = pos.plus(delta); r.size = size.minus(delta.mult(2.f)); return r; } Vec interpolate(Vec p) { return pos.plus(size.mult(p)); } bool isContaining(Vec v) const { return contains(v); } bool isIntersecting(Rect r) const { return intersects(r); } bool isEqual(Rect r) const { return equals(r); } }; inline Vec Vec::clamp(Rect bound) const { return Vec(math::clamp(x, bound.pos.x, bound.pos.x + bound.size.x), math::clamp(y, bound.pos.y, bound.pos.y + bound.size.y)); } inline Vec Vec::clampSafe(Rect bound) const { return Vec(math::clampSafe(x, bound.pos.x, bound.pos.x + bound.size.x), math::clampSafe(y, bound.pos.y, bound.pos.y + bound.size.y)); } inline Vec operator+(const Vec& a) { return a; } inline Vec operator-(const Vec& a) { return a.neg(); } inline Vec operator+(const Vec& a, const Vec& b) { return a.plus(b); } inline Vec operator-(const Vec& a, const Vec& b) { return a.minus(b); } inline Vec operator*(const Vec& a, const Vec& b) { return a.mult(b); } inline Vec operator*(const Vec& a, const float& b) { return a.mult(b); } inline Vec operator*(const float& a, const Vec& b) { return b.mult(a); } inline Vec operator/(const Vec& a, const Vec& b) { return a.div(b); } inline Vec operator/(const Vec& a, const float& b) { return a.div(b); } inline Vec operator+=(Vec& a, const Vec& b) { return a = a.plus(b); } inline Vec operator-=(Vec& a, const Vec& b) { return a = a.minus(b); } inline Vec operator*=(Vec& a, const Vec& b) { return a = a.mult(b); } inline Vec operator*=(Vec& a, const float& b) { return a = a.mult(b); } inline Vec operator/=(Vec& a, const Vec& b) { return a = a.div(b); } inline Vec operator/=(Vec& a, const float& b) { return a = a.div(b); } inline bool operator==(const Vec& a, const Vec& b) { return a.equals(b); } inline bool operator!=(const Vec& a, const Vec& b) { return !a.equals(b); } inline bool operator==(const Rect& a, const Rect& b) { return a.equals(b); } inline bool operator!=(const Rect& a, const Rect& b) { return !a.equals(b); } } // namespace math namespace engine { static constexpr const int PORT_MAX_CHANNELS = 16; struct Module; struct Engine { float getSampleRate() { return sampleRate; } // custom float sampleRate = 0.f; }; struct Light { float value = 0.f; inline void setBrightness(float brightness) { value = brightness; } inline float getBrightness() { return value; } inline void setBrightnessSmooth(float brightness, float deltaTime, float lambda = 30.f) { if (brightness < value) { // Fade out light value += (brightness - value) * lambda * deltaTime; } else { // Immediately illuminate light value = brightness; } } inline void setSmoothBrightness(float brightness, float deltaTime) { setBrightnessSmooth(brightness, deltaTime); } inline void setBrightnessSmooth(float brightness, int frames = 1) { setBrightnessSmooth(brightness, frames / 44100.f); } }; struct LightInfo { Module* module = NULL; int lightId = -1; std::string name; std::string description; virtual ~LightInfo() {} virtual std::string getName() { return name; } virtual std::string getDescription() { return description; } }; struct Param { float value = 0.f; inline float getValue() { return value; } inline void setValue(float value) { this->value = value; } }; struct Port { union { float voltages[PORT_MAX_CHANNELS] = {}; float value; }; union { uint8_t channels = 0; uint8_t active; }; Light plugLights[3]; enum Type { INPUT, OUTPUT, }; inline void setVoltage(float voltage, int channel = 0) { voltages[channel] = voltage; } inline float getVoltage(int channel = 0) { return voltages[channel]; } inline float getPolyVoltage(int channel) { return isMonophonic() ? getVoltage(0) : getVoltage(channel); } inline float getNormalVoltage(float normalVoltage, int channel = 0) { return isConnected() ? getVoltage(channel) : normalVoltage; } inline float getNormalPolyVoltage(float normalVoltage, int channel) { return isConnected() ? getPolyVoltage(channel) : normalVoltage; } inline float* getVoltages(int firstChannel = 0) { return &voltages[firstChannel]; } inline void readVoltages(float* v) { for (int c = 0; c < channels; c++) { v[c] = voltages[c]; } } inline void writeVoltages(const float* v) { for (int c = 0; c < channels; c++) { voltages[c] = v[c]; } } inline void clearVoltages() { for (int c = 0; c < channels; c++) { voltages[c] = 0.f; } } inline float getVoltageSum() { float sum = 0.f; for (int c = 0; c < channels; c++) { sum += voltages[c]; } return sum; } inline float getVoltageRMS() { if (channels == 0) { return 0.f; } else if (channels == 1) { return std::fabs(voltages[0]); } else { float sum = 0.f; for (int c = 0; c < channels; c++) { sum += std::pow(voltages[c], 2); } return std::sqrt(sum); } } // template // T getVoltageSimd(int firstChannel) { // return T::load(&voltages[firstChannel]); // } // // template // T getPolyVoltageSimd(int firstChannel) { // return isMonophonic() ? getVoltage(0) : getVoltageSimd(firstChannel); // } // // template // T getNormalVoltageSimd(T normalVoltage, int firstChannel) { // return isConnected() ? getVoltageSimd(firstChannel) : normalVoltage; // } // // template // T getNormalPolyVoltageSimd(T normalVoltage, int firstChannel) { // return isConnected() ? getPolyVoltageSimd(firstChannel) : normalVoltage; // } // // template // void setVoltageSimd(T voltage, int firstChannel) { // voltage.store(&voltages[firstChannel]); // } inline void setChannels(int channels) { if (this->channels == 0) { return; } for (int c = channels; c < this->channels; c++) { voltages[c] = 0.f; } if (channels == 0) { channels = 1; } this->channels = channels; } inline int getChannels() { return channels; } inline bool isConnected() { return channels > 0; } inline bool isMonophonic() { return channels == 1; } inline bool isPolyphonic() { return channels > 1; } inline float normalize(float normalVoltage) { return getNormalVoltage(normalVoltage); } }; struct Output : Port {}; struct Input : Port {}; struct PortInfo { Module* module = NULL; Port::Type type = Port::INPUT; int portId = -1; std::string name; std::string description; virtual ~PortInfo() {} virtual std::string getName() { if (name == "") return std::string("#") + std::to_string(portId + 1); return name; } std::string getFullName() { std::string name = getName(); name += " "; name += (type == Port::INPUT) ? "input" : "output"; return name; } virtual std::string getDescription() { return description; } }; struct ParamQuantity : Quantity { Module* module = NULL; int paramId = -1; float minValue = 0.f; float maxValue = 1.f; float defaultValue = 0.f; std::string name; std::string unit; float displayBase = 0.f; float displayMultiplier = 1.f; float displayOffset = 0.f; int displayPrecision = 5; std::string description; bool resetEnabled = true; bool randomizeEnabled = true; bool smoothEnabled = false; bool snapEnabled = false; // Param* getParam(); // /** If smoothEnabled is true, requests to the engine to smoothly move to a target value each sample. */ // void setSmoothValue(float value); // float getSmoothValue(); // void setValue(float value) override; // float getValue() override; inline float getMinValue() override { return minValue; } inline float getMaxValue() override { return maxValue; } inline float getDefaultValue() override { return defaultValue; } // float getDisplayValue() override; // void setDisplayValue(float displayValue) override; // std::string getDisplayValueString() override; // void setDisplayValueString(std::string s) override; // int getDisplayPrecision() override; // std::string getLabel() override; // std::string getUnit() override; // void reset() override; // void randomize() override; virtual std::string getDescription() { return description; } // virtual json_t* toJson(); // virtual void fromJson(json_t* rootJ); }; struct SwitchQuantity : ParamQuantity { // std::vector labels; // std::string getDisplayValueString() override; // void setDisplayValueString(std::string s) override; }; struct Module { std::vector params; std::vector inputs; std::vector outputs; std::vector lights; std::vector paramQuantities; std::vector inputInfos; std::vector outputInfos; std::vector lightInfos; virtual ~Module() { for (ParamQuantity* paramQuantity : paramQuantities) { if (paramQuantity) delete paramQuantity; } for (PortInfo* inputInfo : inputInfos) { if (inputInfo) delete inputInfo; } for (PortInfo* outputInfo : outputInfos) { if (outputInfo) delete outputInfo; } for (LightInfo* lightInfo : lightInfos) { if (lightInfo) delete lightInfo; } } void config(int numParams, int numInputs, int numOutputs, int numLights = 0) { params.resize(numParams); inputs.resize(numInputs); outputs.resize(numOutputs); lights.resize(numLights); paramQuantities.resize(numParams); for (int i = 0; i < numParams; i++) { configParam(i, 0.f, 1.f, 0.f); } inputInfos.resize(numInputs); for (int i = 0; i < numInputs; i++) { configInput(i); } outputInfos.resize(numOutputs); for (int i = 0; i < numOutputs; i++) { configOutput(i); } lightInfos.resize(numLights); for (int i = 0; i < numLights; i++) { configLight(i); } } template TParamQuantity* configParam(int paramId, float minValue, float maxValue, float defaultValue, std::string name = "", std::string unit = "", float displayBase = 0.f, float displayMultiplier = 1.f, float displayOffset = 0.f) { if (paramQuantities[paramId]) delete paramQuantities[paramId]; TParamQuantity* q = new TParamQuantity; q->ParamQuantity::module = this; q->ParamQuantity::paramId = paramId; q->ParamQuantity::minValue = minValue; q->ParamQuantity::maxValue = maxValue; q->ParamQuantity::defaultValue = defaultValue; q->ParamQuantity::name = name; q->ParamQuantity::unit = unit; q->ParamQuantity::displayBase = displayBase; q->ParamQuantity::displayMultiplier = displayMultiplier; q->ParamQuantity::displayOffset = displayOffset; paramQuantities[paramId] = q; Param* p = ¶ms[paramId]; p->value = q->getDefaultValue(); return q; } template TSwitchQuantity* configSwitch(int paramId, float minValue, float maxValue, float defaultValue, std::string name = "", std::vector labels = {}) { TSwitchQuantity* sq = configParam(paramId, minValue, maxValue, defaultValue, name); sq->labels = labels; return sq; } template TSwitchQuantity* configButton(int paramId, std::string name = "") { TSwitchQuantity* sq = configParam(paramId, 0.f, 1.f, 0.f, name); sq->randomizeEnabled = false; return sq; } template TPortInfo* configInput(int portId, std::string name = "") { if (inputInfos[portId]) delete inputInfos[portId]; TPortInfo* info = new TPortInfo; info->PortInfo::module = this; info->PortInfo::type = Port::INPUT; info->PortInfo::portId = portId; info->PortInfo::name = name; inputInfos[portId] = info; return info; } template TPortInfo* configOutput(int portId, std::string name = "") { if (outputInfos[portId]) delete outputInfos[portId]; TPortInfo* info = new TPortInfo; info->PortInfo::module = this; info->PortInfo::type = Port::OUTPUT; info->PortInfo::portId = portId; info->PortInfo::name = name; outputInfos[portId] = info; return info; } template TLightInfo* configLight(int lightId, std::string name = "") { if (lightInfos[lightId]) delete lightInfos[lightId]; TLightInfo* info = new TLightInfo; info->LightInfo::module = this; info->LightInfo::lightId = lightId; info->LightInfo::name = name; lightInfos[lightId] = info; return info; } void configBypass(int inputId, int outputId) { // // Check that output is not yet routed // for (BypassRoute& br : bypassRoutes) { // assert(br.outputId != outputId); // } // BypassRoute br; // br.inputId = inputId; // br.outputId = outputId; // bypassRoutes.push_back(br); } int getNumParams() { return params.size(); } Param& getParam(int index) { return params[index]; } int getNumInputs() { return inputs.size(); } Input& getInput(int index) { return inputs[index]; } int getNumOutputs() { return outputs.size(); } Output& getOutput(int index) { return outputs[index]; } int getNumLights() { return lights.size(); } Light& getLight(int index) { return lights[index]; } ParamQuantity* getParamQuantity(int index) { return paramQuantities[index]; } PortInfo* getInputInfo(int index) { return inputInfos[index]; } PortInfo* getOutputInfo(int index) { return outputInfos[index]; } LightInfo* getLightInfo(int index) { return lightInfos[index]; } struct ProcessArgs { float sampleRate; float sampleTime; int64_t frame; }; virtual void process(const ProcessArgs& args) { step(); } virtual void step() {} // virtual void processBypass(const ProcessArgs& args); // virtual json_t* toJson(); // virtual void fromJson(json_t* rootJ); // virtual json_t* paramsToJson(); // virtual void paramsFromJson(json_t* rootJ); virtual json_t* dataToJson() { return NULL; } virtual void dataFromJson(json_t* rootJ) {} struct SampleRateChangeEvent { float sampleRate; float sampleTime; }; virtual void onSampleRateChange(const SampleRateChangeEvent&) { onSampleRateChange(); } struct ResetEvent {}; virtual void onReset(const ResetEvent&) {} // TODO virtual void onAdd() {} virtual void onRemove() {} virtual void onReset() {} virtual void onRandomize() {} virtual void onSampleRateChange() {} // private void doProcess(const ProcessArgs& args) { // if (!internal->bypassed) process(args); // else // processBypass(args); // if (args.frame % PORT_DIVIDER == 0) { // float portTime = args.sampleTime * PORT_DIVIDER; // for (Input& input : inputs) { // Port_step(&input, portTime); // } // for (Output& output : outputs) { // Port_step(&output, portTime); // } // } } }; } // namespace engine namespace widget { struct BaseEvent { }; struct Widget { math::Rect box; Widget* parent = NULL; std::list children; bool visible = false; bool requestedDelete = false; virtual ~Widget() {} math::Rect getBox() { return {}; } void setBox(math::Rect box) {} math::Vec getPosition() { return {}; } void setPosition(math::Vec pos) {} math::Vec getSize() { return {}; } void setSize(math::Vec size) {} widget::Widget* getParent() { return NULL; } bool isVisible() { return false; } void setVisible(bool visible) {} void show() {} void hide() {} void requestDelete() {} virtual math::Rect getChildrenBoundingBox() { return {}; } virtual math::Rect getVisibleChildrenBoundingBox() { return {}; } bool isDescendantOf(Widget* ancestor) { return false; } virtual math::Vec getRelativeOffset(math::Vec v, Widget* ancestor) { return {}; } math::Vec getAbsoluteOffset(math::Vec v) { return {}; } virtual float getRelativeZoom(Widget* ancestor) { return 0.f; } float getAbsoluteZoom() { return 0.f; } virtual math::Rect getViewport(math::Rect r) { return {}; } template T* getAncestorOfType() { return NULL; } template T* getFirstDescendantOfType() { return NULL; } bool hasChild(Widget* child) { return false; } void addChild(Widget* child) {} void addChildBottom(Widget* child) {} void addChildBelow(Widget* child, Widget* sibling) {} void addChildAbove(Widget* child, Widget* sibling) {} void removeChild(Widget* child) {} void clearChildren() {} virtual void step() {} struct DrawArgs { NVGcontext* vg = NULL; math::Rect clipBox; void* fb = NULL; }; virtual void draw(const DrawArgs&) {} // DEPRECATED virtual void draw(NVGcontext* vg) {} virtual void drawLayer(const DrawArgs& args, int layer) {} void drawChild(Widget* child, const DrawArgs& args, int layer = 0) {} using BaseEvent = widget::BaseEvent; struct PositionBaseEvent { math::Vec pos; }; struct HoverEvent : BaseEvent, PositionBaseEvent { math::Vec mouseDelta; }; virtual void onHover(const HoverEvent&) {} struct ButtonEvent : BaseEvent, PositionBaseEvent { int button; int action; int mods; }; virtual void onButton(const ButtonEvent&) {} struct DoubleClickEvent : BaseEvent {}; virtual void onDoubleClick(const DoubleClickEvent&) {} struct KeyBaseEvent { int key; int scancode; std::string keyName; int action; int mods; }; struct HoverKeyEvent : BaseEvent, PositionBaseEvent, KeyBaseEvent {}; virtual void onHoverKey(const HoverKeyEvent&) {} struct TextBaseEvent { int codepoint; }; struct HoverTextEvent : BaseEvent, PositionBaseEvent, TextBaseEvent {}; virtual void onHoverText(const HoverTextEvent&) {} struct HoverScrollEvent : BaseEvent, PositionBaseEvent { math::Vec scrollDelta; }; virtual void onHoverScroll(const HoverScrollEvent&) {} struct EnterEvent : BaseEvent {}; virtual void onEnter(const EnterEvent&) {} struct LeaveEvent : BaseEvent {}; virtual void onLeave(const LeaveEvent&) {} struct SelectEvent : BaseEvent {}; virtual void onSelect(const SelectEvent&) {} struct DeselectEvent : BaseEvent {}; virtual void onDeselect(const DeselectEvent&) {} struct SelectKeyEvent : BaseEvent, KeyBaseEvent {}; virtual void onSelectKey(const SelectKeyEvent&) {} struct SelectTextEvent : BaseEvent, TextBaseEvent {}; virtual void onSelectText(const SelectTextEvent&) {} struct DragBaseEvent : BaseEvent { int button; }; struct DragStartEvent : DragBaseEvent {}; virtual void onDragStart(const DragStartEvent&) {} struct DragEndEvent : DragBaseEvent {}; virtual void onDragEnd(const DragEndEvent&) {} struct DragMoveEvent : DragBaseEvent { math::Vec mouseDelta; }; virtual void onDragMove(const DragMoveEvent&) {} struct DragHoverEvent : DragBaseEvent, PositionBaseEvent { Widget* origin = NULL; math::Vec mouseDelta; }; virtual void onDragHover(const DragHoverEvent&) { } struct DragEnterEvent : DragBaseEvent { Widget* origin = NULL; }; virtual void onDragEnter(const DragEnterEvent&) {} struct DragLeaveEvent : DragBaseEvent { Widget* origin = NULL; }; virtual void onDragLeave(const DragLeaveEvent&) {} struct DragDropEvent : DragBaseEvent { Widget* origin = NULL; }; virtual void onDragDrop(const DragDropEvent&) {} struct PathDropEvent : BaseEvent, PositionBaseEvent { PathDropEvent(const std::vector& paths) : paths(paths) {} const std::vector& paths; }; virtual void onPathDrop(const PathDropEvent&) {} struct ActionEvent : BaseEvent {}; virtual void onAction(const ActionEvent&) {} struct ChangeEvent : BaseEvent {}; virtual void onChange(const ChangeEvent&) {} struct DirtyEvent : BaseEvent {}; virtual void onDirty(const DirtyEvent&) {} struct RepositionEvent : BaseEvent {}; virtual void onReposition(const RepositionEvent&) {} struct ResizeEvent : BaseEvent {}; virtual void onResize(const ResizeEvent&) {} struct AddEvent : BaseEvent {}; virtual void onAdd(const AddEvent&) {} struct RemoveEvent : BaseEvent {}; virtual void onRemove(const RemoveEvent&) {} struct ShowEvent : BaseEvent {}; virtual void onShow(const ShowEvent&) {} struct HideEvent : BaseEvent {}; virtual void onHide(const HideEvent&) {} struct ContextCreateEvent : BaseEvent { NVGcontext* vg; }; virtual void onContextCreate(const ContextCreateEvent&) {} struct ContextDestroyEvent : BaseEvent { NVGcontext* vg; }; virtual void onContextDestroy(const ContextDestroyEvent&) {} }; struct OpaqueWidget : Widget { }; struct SvgWidget : Widget { std::shared_ptr svg; void wrap() {} void setSvg(std::shared_ptr) {} }; struct TransparentWidget : Widget { }; } // namespace widget namespace app { static constexpr const float RACK_GRID_WIDTH = 15; static constexpr const float RACK_GRID_HEIGHT = 380; static const math::Vec RACK_GRID_SIZE = math::Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT); static const math::Vec RACK_OFFSET = RACK_GRID_SIZE.mult(math::Vec(2000, 100)); struct ParamWidget; struct PortWidget; struct CircularShadow : widget::TransparentWidget { float blurRadius; float opacity; }; struct LightWidget : widget::TransparentWidget { NVGcolor bgColor, color, borderColor; }; struct ModuleWidget : widget::OpaqueWidget { // plugin::Model* model = NULL; engine::Module* module = NULL; // plugin::Model* getModel() { return NULL; } // void setModel(plugin::Model*) {} engine::Module* getModule() { return NULL; } void setModule(engine::Module*) {} widget::Widget* getPanel() { return NULL; } void setPanel(widget::Widget*) {} void setPanel(std::shared_ptr) {} void addParam(ParamWidget*) {} void addInput(PortWidget*) {} void addOutput(PortWidget*) {} ParamWidget* getParam(int paramId) { return NULL; } PortWidget* getInput(int portId) { return NULL; } PortWidget* getOutput(int portId) { return NULL; } std::vector getParams() { return {}; } std::vector getPorts() { return {}; } std::vector getInputs() { return {}; } std::vector getOutputs() { return {}; } virtual void appendContextMenu(ui::Menu*) {} json_t* toJson() { return NULL; } void fromJson(json_t*) {} bool pasteJsonAction(json_t*) { return false; } void copyClipboard() {} bool pasteClipboardAction() { return false; } void load(std::string) {} void loadAction(std::string) {} void loadTemplate() {} void loadDialog() {} void save(std::string) {} void saveTemplate() {} void saveTemplateDialog() {} bool hasTemplate() { return false; } void clearTemplate() {} void clearTemplateDialog() {} void saveDialog() {} void disconnect() {} void resetAction() {} void randomizeAction() {} void appendDisconnectActions(/*history::ComplexAction*/void*) {} void disconnectAction() {} void cloneAction(bool cc = true) {} void bypassAction(bool) {} void removeAction() {} void createContextMenu() {} }; struct MultiLightWidget : LightWidget { // std::vector baseColors; // int getNumColors(); void addBaseColor(NVGcolor baseColor) {} // void setBrightnesses(const std::vector& brightnesses); }; struct ModuleLightWidget : MultiLightWidget { // engine::Module* module = NULL; // int firstLightId = -1; // ModuleLightWidget(); // ~ModuleLightWidget(); // engine::Light* getLight(int colorId); // engine::LightInfo* getLightInfo(); // void createTooltip(); // void destroyTooltip(); }; struct ParamWidget : widget::OpaqueWidget { engine::Module* module = NULL; int paramId = -1; virtual void initParamQuantity() {} engine::ParamQuantity* getParamQuantity() { return module ? module->paramQuantities[paramId] : NULL; } void createTooltip() {} void destroyTooltip() {} void createContextMenu(); virtual void appendContextMenu(void* menu) {} void resetAction(); }; struct PortWidget : widget::OpaqueWidget { }; struct Knob : ParamWidget { bool horizontal = false; bool smooth = true; bool snap = false; float speed = 1.f; bool forceLinear = false; float minAngle = -M_PI; float maxAngle = M_PI; }; struct SliderKnob : Knob { }; struct Switch : ParamWidget { bool momentary = false; }; struct SvgKnob : Knob { // widget::FramebufferWidget* fb; CircularShadow* shadow; // widget::TransformWidget* tw; widget::SvgWidget* sw; void setSvg(std::shared_ptr) {} }; struct SvgPanel : widget::Widget { // widget::FramebufferWidget* fb; // widget::SvgWidget* sw; // PanelBorder* panelBorder; void setBackground(std::shared_ptr) {} }; struct SvgPort : PortWidget { // widget::FramebufferWidget* fb; CircularShadow* shadow; // widget::SvgWidget* sw; void setSvg(std::shared_ptr) {} }; struct SvgScrew : widget::Widget { // widget::FramebufferWidget* fb; widget::SvgWidget* sw; void setSvg(std::shared_ptr) {} }; struct SvgSlider : app::SliderKnob { // widget::FramebufferWidget* fb; widget::SvgWidget* background; widget::SvgWidget* handle; math::Vec minHandlePos, maxHandlePos; void setBackgroundSvg(std::shared_ptr) {} void setHandleSvg(std::shared_ptr) {} void setHandlePos(math::Vec minHandlePos, math::Vec maxHandlePos) {} void setHandlePosCentered(math::Vec minHandlePosCentered, math::Vec maxHandlePosCentered) {} }; struct SvgSwitch : Switch { // widget::FramebufferWidget* fb; // CircularShadow* shadow; // widget::SvgWidget* sw; // std::vector> frames; bool latch = false; void addFrame(std::shared_ptr) {} }; struct Scene : widget::OpaqueWidget { // RackScrollWidget* rackScroll; // RackWidget* rack; widget::Widget* menuBar; widget::Widget* browser; math::Vec getMousePos() { return {}; } }; } // namespace app namespace asset { inline std::string plugin(void* instance, const char* path) { return {}; } inline std::string system(const char* path) { return {}; } } // namespace asset namespace componentlibrary { static constexpr const NVGcolor SCHEME_BLACK_TRANSPARENT = {}; static constexpr const NVGcolor SCHEME_BLACK = {}; static constexpr const NVGcolor SCHEME_WHITE = {}; static constexpr const NVGcolor SCHEME_RED = {}; static constexpr const NVGcolor SCHEME_ORANGE = {}; static constexpr const NVGcolor SCHEME_YELLOW = {}; static constexpr const NVGcolor SCHEME_GREEN = {}; static constexpr const NVGcolor SCHEME_CYAN = {}; static constexpr const NVGcolor SCHEME_BLUE = {}; static constexpr const NVGcolor SCHEME_PURPLE = {}; static constexpr const NVGcolor SCHEME_LIGHT_GRAY = {}; static constexpr const NVGcolor SCHEME_DARK_GRAY = {}; template struct TSvgLight : TBase { // widget::FramebufferWidget* fb; // widget::SvgWidget* sw; void setSvg(std::shared_ptr) {} }; using SvgLight = TSvgLight<>; template struct TGrayModuleLightWidget : TBase {}; using GrayModuleLightWidget = TGrayModuleLightWidget<>; template struct TWhiteLight : TBase {}; using WhiteLight = TWhiteLight<>; template struct TRedLight : TBase {}; using RedLight = TRedLight<>; template struct TGreenLight : TBase {}; using GreenLight = TGreenLight<>; template struct TBlueLight : TBase {}; using BlueLight = TBlueLight<>; template struct TYellowLight : TBase {}; using YellowLight = TYellowLight<>; template struct TGreenRedLight : TBase {}; using GreenRedLight = TGreenRedLight<>; template struct TRedGreenBlueLight : TBase {}; using RedGreenBlueLight = TRedGreenBlueLight<>; template struct LargeLight : TSvgLight {}; template struct MediumLight : TSvgLight {}; template struct SmallLight : TSvgLight {}; template struct TinyLight : TSvgLight {}; template struct LargeSimpleLight : TBase {}; template struct MediumSimpleLight : TBase {}; template struct SmallSimpleLight : TBase {}; template struct TinySimpleLight : TBase {}; template struct RectangleLight : TBase {}; template struct VCVBezelLight : TBase {}; template using LEDBezelLight = VCVBezelLight; template struct PB61303Light : TBase {}; struct RoundKnob : app::SvgKnob { widget::SvgWidget* bg; }; struct RoundBlackKnob : RoundKnob {}; struct RoundSmallBlackKnob : RoundKnob {}; struct RoundLargeBlackKnob : RoundKnob {}; struct RoundBigBlackKnob : RoundKnob {}; struct RoundHugeBlackKnob : RoundKnob {}; struct RoundBlackSnapKnob : RoundBlackKnob {}; struct Davies1900hKnob : app::SvgKnob {}; struct Davies1900hWhiteKnob : Davies1900hKnob {}; struct Davies1900hBlackKnob : Davies1900hKnob {}; struct Davies1900hRedKnob : Davies1900hKnob {}; struct Davies1900hLargeWhiteKnob : Davies1900hKnob {}; struct Davies1900hLargeBlackKnob : Davies1900hKnob {}; struct Davies1900hLargeRedKnob : Davies1900hKnob {}; struct Rogan : app::SvgKnob { widget::SvgWidget* bg; widget::SvgWidget* fg; }; struct Rogan6PSWhite : Rogan {}; struct Rogan5PSGray : Rogan {}; struct Rogan3PSBlue : Rogan {}; struct Rogan3PSRed : Rogan {}; struct Rogan3PSGreen : Rogan {}; struct Rogan3PSWhite : Rogan {}; struct Rogan3PBlue : Rogan {}; struct Rogan3PRed : Rogan {}; struct Rogan3PGreen : Rogan {}; struct Rogan3PWhite : Rogan {}; struct Rogan2SGray : Rogan {}; struct Rogan2PSBlue : Rogan {}; struct Rogan2PSRed : Rogan {}; struct Rogan2PSGreen : Rogan {}; struct Rogan2PSWhite : Rogan {}; struct Rogan2PBlue : Rogan {}; struct Rogan2PRed : Rogan {}; struct Rogan2PGreen : Rogan {}; struct Rogan2PWhite : Rogan {}; struct Rogan1PSBlue : Rogan {}; struct Rogan1PSRed : Rogan {}; struct Rogan1PSGreen : Rogan {}; struct Rogan1PSWhite : Rogan {}; struct Rogan1PBlue : Rogan {}; struct Rogan1PRed : Rogan {}; struct Rogan1PGreen : Rogan {}; struct Rogan1PWhite : Rogan {}; struct SynthTechAlco : app::SvgKnob { widget::SvgWidget* bg; }; struct Trimpot : app::SvgKnob { widget::SvgWidget* bg; }; struct BefacoBigKnob : app::SvgKnob { widget::SvgWidget* bg; }; struct BefacoTinyKnob : app::SvgKnob { widget::SvgWidget* bg; }; struct BefacoSlidePot : app::SvgSlider {}; struct VCVSlider : app::SvgSlider {}; using LEDSlider = VCVSlider; struct VCVSliderHorizontal : app::SvgSlider {}; using LEDSliderHorizontal = VCVSliderHorizontal; template struct LightSlider : TBase { app::ModuleLightWidget* light = NULL; app::ModuleLightWidget* getLight() { return light; } }; template struct VCVSliderLight : RectangleLight> {}; template using LEDSliderLight = VCVSliderLight; template struct VCVLightSlider : LightSlider> {}; template using LEDLightSlider = VCVLightSlider; struct LEDSliderGreen : VCVLightSlider {}; struct LEDSliderRed : VCVLightSlider {}; struct LEDSliderYellow : VCVLightSlider {}; struct LEDSliderBlue : VCVLightSlider {}; struct LEDSliderWhite : VCVLightSlider {}; template struct VCVLightSliderHorizontal : LightSlider {}; template using LEDLightSliderHorizontal = VCVLightSliderHorizontal; struct PJ301MPort : app::SvgPort {}; struct PJ3410Port : app::SvgPort {}; struct CL1362Port : app::SvgPort {}; template struct MomentarySwitch : TSwitch {}; struct NKK : app::SvgSwitch {}; struct CKSS : app::SvgSwitch {}; struct CKSSThree : app::SvgSwitch {}; struct CKSSThreeHorizontal : app::SvgSwitch {}; struct CKD6 : app::SvgSwitch {}; struct TL1105 : app::SvgSwitch {}; struct VCVButton : app::SvgSwitch {}; using LEDButton = VCVButton; struct VCVLatch : VCVButton {}; template struct VCVLightButton : VCVButton { app::ModuleLightWidget* light = NULL; app::ModuleLightWidget* getLight() { return light; } }; template using LEDLightButton = VCVLightButton; template struct VCVLightLatch : VCVLightButton {}; struct BefacoSwitch : app::SvgSwitch {}; struct BefacoPush : app::SvgSwitch {}; struct VCVBezel : app::SvgSwitch {}; using LEDBezel = VCVBezel; struct VCVBezelLatch : VCVBezel {}; template struct VCVLightBezel : VCVBezel { app::ModuleLightWidget* light = NULL; app::ModuleLightWidget* getLight() { return light; } }; template using LEDLightBezel = VCVLightBezel; template struct VCVLightBezelLatch : VCVLightBezel {}; struct PB61303 : app::SvgSwitch {}; struct ScrewSilver : app::SvgScrew {}; struct ScrewBlack : app::SvgScrew {}; } // namespace componentlibrary namespace dsp { static constexpr const float FREQ_C4 = 261.6256f; static constexpr const float FREQ_A4 = 440.0000f; static constexpr const float FREQ_SEMITONE = 1.0594630943592953f; inline float sinc(float x) { if (x == 0.f) return 1.f; x *= M_PI; return std::sin(x) / x; } // template // T sinc(T x) { // T zeromask = (x == 0.f); // x *= M_PI; // x = simd::sin(x) / x; // return simd::ifelse(zeromask, 1.f, x); // } // template // T amplitudeToDb(T amp) { // return simd::log10(amp) * 20; // } template T dbToAmplitude(T db) { return std::pow(10, db / 20); } // template // T quadraticBipolar(T x) { // return simd::sgn(x) * (x * x); // } template T cubic(T x) { return x * x * x; } // template // T quarticBipolar(T x) { // return simd::sgn(x) * (x * x * x * x); // } template T quintic(T x) { return x * x * x * x * x; } // template // T sqrtBipolar(T x) { // return simd::sgn(x) * simd::sqrt(x); // } // template // T exponentialBipolar(T b, T x) { // return (simd::pow(b, x) - simd::pow(b, -x)) / (b - 1.f / b); // } template struct Frame { T samples[CHANNELS]; }; template inline T blackmanHarris(T p) { return + T(0.35875) - T(0.48829) * std::cos(2 * T(M_PI) * p) + T(0.14128) * std::cos(4 * T(M_PI) * p) - T(0.01168) * std::cos(6 * T(M_PI) * p); } inline void blackmanHarrisWindow(float* x, int len) { for (int i = 0; i < len; i++) { x[i] *= blackmanHarris(float(i) / (len - 1)); } } inline void boxcarLowpassIR(float* out, int len, float cutoff = 0.5f) { for (int i = 0; i < len; i++) { float t = i - (len - 1) / 2.f; out[i] = 2 * cutoff * sinc(2 * cutoff * t); } } struct BooleanTrigger { bool state = true; void reset() { state = true; } bool process(bool state) { bool triggered = (state && !this->state); this->state = state; return triggered; } }; template struct TSchmittTrigger { T state; TSchmittTrigger() { reset(); } void reset() { state = T::mask(); } T process(T in, T offThreshold = 0.f, T onThreshold = 1.f) { T on = (in >= onThreshold); T off = (in <= offThreshold); T triggered = ~state & on; state = on | (state & ~off); return triggered; } T isHigh() { return state; } }; template <> struct TSchmittTrigger { bool state = true; void reset() { state = true; } bool process(float in, float offThreshold = 0.f, float onThreshold = 1.f) { if (state) { if (in <= offThreshold) { state = false; } } else { if (in >= onThreshold) { state = true; return true; } } return false; } bool isHigh() { return state; } }; typedef TSchmittTrigger<> SchmittTrigger; struct PulseGenerator { float remaining = 0.f; void reset() { remaining = 0.f; } bool process(float deltaTime) { if (remaining > 0.f) { remaining -= deltaTime; return true; } return false; } void trigger(float duration = 1e-3f) { if (duration > remaining) { remaining = duration; } } }; template struct TTimer { T time = 0.f; void reset() { time = 0.f; } T process(T deltaTime) { time += deltaTime; return time; } T getTime() { return time; } }; typedef TTimer<> Timer; struct ClockDivider { uint32_t clock = 0; uint32_t division = 1; void reset() { clock = 0; } void setDivision(uint32_t division) { this->division = division; } uint32_t getDivision() { return division; } uint32_t getClock() { return clock; } bool process() { clock++; if (clock >= division) { clock = 0; return true; } return false; } }; template struct Decimator { T inBuffer[OVERSAMPLE * QUALITY]; float kernel[OVERSAMPLE * QUALITY]; int inIndex; Decimator(float cutoff = 0.9f) { boxcarLowpassIR(kernel, OVERSAMPLE * QUALITY, cutoff * 0.5f / OVERSAMPLE); blackmanHarrisWindow(kernel, OVERSAMPLE * QUALITY); reset(); } void reset() { inIndex = 0; std::memset(inBuffer, 0, sizeof(inBuffer)); } T process(T* in) { std::memcpy(&inBuffer[inIndex], in, OVERSAMPLE * sizeof(T)); inIndex += OVERSAMPLE; inIndex %= OVERSAMPLE * QUALITY; T out = 0.f; for (int i = 0; i < OVERSAMPLE * QUALITY; i++) { int index = inIndex - 1 - i; index = (index + OVERSAMPLE * QUALITY) % (OVERSAMPLE * QUALITY); out += kernel[i] * inBuffer[index]; } return out; } }; template struct RingBuffer { std::atomic start{0}; std::atomic end{0}; T data[S]; void push(T t) { size_t i = end % S; data[i] = t; end++; } void pushBuffer(const T* t, int n) { size_t i = end % S; size_t e1 = i + n; size_t e2 = (e1 < S) ? e1 : S; std::memcpy(&data[i], t, sizeof(T) * (e2 - i)); if (e1 > S) { std::memcpy(data, &t[S - i], sizeof(T) * (e1 - S)); } end += n; } T shift() { size_t i = start % S; T t = data[i]; start++; return t; } void shiftBuffer(T* t, size_t n) { size_t i = start % S; size_t s1 = i + n; size_t s2 = (s1 < S) ? s1 : S; std::memcpy(t, &data[i], sizeof(T) * (s2 - i)); if (s1 > S) { std::memcpy(&t[S - i], data, sizeof(T) * (s1 - S)); } start += n; } void clear() { start = end.load(); } bool empty() const { return start >= end; } bool full() const { return end - start >= S; } size_t size() const { return end - start; } size_t capacity() const { return S - size(); } }; template struct DoubleRingBuffer { std::atomic start{0}; std::atomic end{0}; T data[2 * S]; void push(T t) { size_t i = end % S; data[i] = t; data[i + S] = t; end++; } T shift() { size_t i = start % S; T t = data[i]; start++; return t; } void clear() { start = end.load(); } bool empty() const { return start >= end; } bool full() const { return end - start >= S; } size_t size() const { return end - start; } size_t capacity() const { return S - size(); } T* endData() { size_t i = end % S; return &data[i]; } void endIncr(size_t n) { size_t i = end % S; size_t e1 = i + n; size_t e2 = (e1 < S) ? e1 : S; std::memcpy(&data[S + i], &data[i], sizeof(T) * (e2 - i)); if (e1 > S) { std::memcpy(data, &data[S], sizeof(T) * (e1 - S)); } end += n; } const T* startData() const { size_t i = start % S; return &data[i]; } void startIncr(size_t n) { start += n; } }; template struct AppleRingBuffer { size_t start = 0; size_t end = 0; T data[N]; void returnBuffer() { size_t s = size(); std::memmove(data, &data[start], sizeof(T) * s); start = 0; end = s; } void push(T t) { if (end + 1 > N) { returnBuffer(); } data[end++] = t; } T shift() { return data[start++]; } bool empty() const { return start == end; } bool full() const { return end - start == S; } size_t size() const { return end - start; } size_t capacity() const { return S - size(); } T* endData(size_t n) { if (end + n > N) { returnBuffer(); } return &data[end]; } void endIncr(size_t n) { end += n; } const T* startData() const { return &data[start]; } void startIncr(size_t n) { start += n; } }; } // namespace dsp namespace event { using Base = widget::BaseEvent; using PositionBase = widget::Widget::PositionBaseEvent; using KeyBase = widget::Widget::KeyBaseEvent; using TextBase = widget::Widget::TextBaseEvent; using Hover = widget::Widget::HoverEvent; using Button = widget::Widget::ButtonEvent; using DoubleClick = widget::Widget::DoubleClickEvent; using HoverKey = widget::Widget::HoverKeyEvent; using HoverText = widget::Widget::HoverTextEvent; using HoverScroll = widget::Widget::HoverScrollEvent; using Enter = widget::Widget::EnterEvent; using Leave = widget::Widget::LeaveEvent; using Select = widget::Widget::SelectEvent; using Deselect = widget::Widget::DeselectEvent; using SelectKey = widget::Widget::SelectKeyEvent; using SelectText = widget::Widget::SelectTextEvent; using DragBase = widget::Widget::DragBaseEvent; using DragStart = widget::Widget::DragStartEvent; using DragEnd = widget::Widget::DragEndEvent; using DragMove = widget::Widget::DragMoveEvent; using DragHover = widget::Widget::DragHoverEvent; using DragEnter = widget::Widget::DragEnterEvent; using DragLeave = widget::Widget::DragLeaveEvent; using DragDrop = widget::Widget::DragDropEvent; using PathDrop = widget::Widget::PathDropEvent; using Action = widget::Widget::ActionEvent; using Change = widget::Widget::ChangeEvent; using Dirty = widget::Widget::DirtyEvent; using Reposition = widget::Widget::RepositionEvent; using Resize = widget::Widget::ResizeEvent; using Add = widget::Widget::AddEvent; using Remove = widget::Widget::RemoveEvent; using Show = widget::Widget::ShowEvent; using Hide = widget::Widget::HideEvent; } // namespace event namespace plugin { struct Model { virtual ~Model() {} virtual engine::Module* createModule() = 0; }; struct Plugin { }; } // namespace plugin namespace random { struct Xoroshiro128Plus { uint64_t state[2] = {}; void seed(uint64_t s0, uint64_t s1) { state[0] = s0; state[1] = s1; operator()(); } bool isSeeded() { return state[0] || state[1]; } static uint64_t rotl(uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } uint64_t operator()() { uint64_t s0 = state[0]; uint64_t s1 = state[1]; uint64_t result = s0 + s1; s1 ^= s0; state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); state[1] = rotl(s1, 36); return result; } constexpr uint64_t min() const { return 0; } constexpr uint64_t max() const { return UINT64_MAX; } }; Xoroshiro128Plus& local(); template T get() { return local()(); } template <> inline uint32_t get() { return get() >> 32; } template <> inline uint16_t get() { return get() >> 48; } template <> inline uint8_t get() { return get() >> 56; } template <> inline bool get() { return get() >> 63; } template <> inline float get() { return get() * 2.32830629e-10f; } template <> inline double get() { return get() * 5.421010862427522e-20; } inline uint64_t u64() { return get(); } inline uint32_t u32() { return get(); } inline float uniform() { return get(); } inline float normal() { const float radius = std::sqrt(-2.f * std::log(1.f - get())); const float theta = 2.f * M_PI * get(); return radius * std::sin(theta); } inline void buffer(uint8_t* out, size_t len) { Xoroshiro128Plus& rng = local(); for (size_t i = 0; i < len; i += 4) { uint64_t r = rng(); out[i] = r; if (i + 1 < len) out[i + 1] = r >> 8; if (i + 2 < len) out[i + 2] = r >> 16; if (i + 3 < len) out[i + 3] = r >> 24; } } inline std::vector vector(size_t len) { std::vector v(len); buffer(v.data(), len); return v; } } // namespace random namespace settings { const bool tooltips = false; } // namespace settings namespace string { inline std::string fV(const char* format, va_list args) { // va_lists cannot be reused but we need it twice, so clone args. va_list args2; va_copy(args2, args); // Compute size of required buffer int size = vsnprintf(NULL, 0, format, args); if (size < 0) return ""; // Create buffer std::string s; s.resize(size); vsnprintf(&s[0], size + 1, format, args2); return s; } __attribute__((format(printf, 1, 2))) inline std::string f(const char* format, ...) { va_list args; va_start(args, format); std::string s = fV(format, args); va_end(args); return s; } } // namespace string namespace ui { struct Button : widget::OpaqueWidget { std::string text; Quantity* quantity = NULL; }; struct ChoiceButton : Button { }; struct Menu : widget::OpaqueWidget { // Menu* parentMenu = NULL; // Menu* childMenu = NULL; // MenuEntry* activeEntry = NULL; // BNDcornerFlags cornerFlags = BND_CORNER_NONE; // void setChildMenu(Menu* menu) {} }; struct MenuEntry : widget::OpaqueWidget { }; struct MenuItem : MenuEntry { std::string text; std::string rightText; bool disabled = false; virtual Menu* createChildMenu() { return NULL; } }; struct MenuLabel : MenuEntry { std::string text; }; struct MenuSeparator : MenuEntry { }; struct Tooltip : widget::Widget { std::string text; }; } // namespace ui namespace window { static constexpr const float SVG_DPI = 75.f; static constexpr const float MM_PER_IN = 25.4f; inline float in2px(float in) { return in * SVG_DPI; } inline math::Vec in2px(math::Vec in) { return in.mult(SVG_DPI); } inline float mm2px(float mm) { return mm * (SVG_DPI / MM_PER_IN); } inline math::Vec mm2px(math::Vec mm) { return mm.mult(SVG_DPI / MM_PER_IN); } struct Svg { // NSVGimage* handle = NULL; // ~Svg(); // /** Don't call this directly. Use `Svg::load()` for caching. */ // void loadFile(const std::string& filename); // void loadString(const std::string& str); // math::Vec getSize(); // int getNumShapes(); // int getNumPaths(); // int getNumPoints(); // void draw(NVGcontext* vg); static std::shared_ptr load(const std::string&) { return {}; } }; inline void svgDraw(NVGcontext*, NSVGimage*) {} struct Font { int handle; }; struct Image { int handle; }; struct Window { inline std::shared_ptr loadFont(const std::string&) { return {}; } inline std::shared_ptr loadImage(const std::string&) { return {}; } inline std::shared_ptr loadSvg(const std::string&) { return {}; } }; }; using namespace app; using namespace componentlibrary; using namespace engine; using namespace math; using namespace ui; using namespace widget; using namespace window; using plugin::Plugin; using plugin::Model; template plugin::Model* createModel(std::string) { struct TModel : plugin::Model { engine::Module* createModule() override { return new TModule; } }; return new TModel; } template T* construct() { return NULL; } template T* construct(F f, V v, Args... args) { return NULL; } template inline TWidget* createWidget(math::Vec pos) { return NULL; } template inline TWidget* createWidgetCentered(math::Vec) { return NULL; } inline app::SvgPanel* createPanel(std::string) { return NULL; } template inline TParamWidget* createParam(math::Vec, engine::Module*, int) { return NULL; } template inline TParamWidget* createParamCentered(math::Vec, engine::Module*, int) { return NULL; } template inline TPortWidget* createInput(math::Vec, engine::Module*, int) { return NULL; } template inline TPortWidget* createInputCentered(math::Vec, engine::Module*, int) { return NULL; } template inline TPortWidget* createOutput(math::Vec pos, engine::Module*, int) { return NULL; } template inline TPortWidget* createOutputCentered(math::Vec pos, engine::Module*, int) { return NULL; } template inline TModuleLightWidget* createLight(math::Vec, engine::Module*, int) { return NULL; } template inline TModuleLightWidget* createLightCentered(math::Vec, engine::Module*, int) { return NULL; } template inline TParamWidget* createLightParam(math::Vec, engine::Module*, int, int) { return NULL; } template inline TParamWidget* createLightParamCentered(math::Vec, engine::Module*, int, int) { return NULL; } template inline TMenu* createMenu() { return NULL; } template inline TMenuLabel* createMenuLabel(std::string) { return NULL; } template inline TMenuItem* createMenuItem(std::string, std::string rt = "") { return NULL; } template inline TMenuItem* createMenuItem(std::string, std::string rightText, std::function, bool d = false, bool ac = false) { return NULL; } template inline ui::MenuItem* createCheckMenuItem(std::string, std::string, std::function, std::function, bool d = false, bool ac = false) { return NULL; } template inline ui::MenuItem* createBoolMenuItem(std::string, std::string, std::function, std::function, bool d = false, bool ac = false) { return NULL; } template inline ui::MenuItem* createBoolPtrMenuItem(std::string, std::string, T*) { return NULL; } template inline ui::MenuItem* createSubmenuItem(std::string, std::string, std::function, bool d = false) { return NULL; } template inline ui::MenuItem* createIndexSubmenuItem(std::string, std::vector, std::function, std::function, bool d = false, bool ac = false) { return NULL; } template inline ui::MenuItem* createIndexPtrSubmenuItem(std::string, std::vector, T*) { return NULL; } struct Context { app::Scene _scene; engine::Engine _engine; window::Window _window; engine::Engine* engine = &_engine; app::Scene* scene = &_scene; window::Window* window = &_window; }; Context* contextGet(); void contextSet(Context* context); } // namespace rack #define APP rack::contextGet()