@@ -7,13 +7,13 @@ | |||||
namespace rack { | namespace rack { | ||||
struct Model; | |||||
struct Module; | struct Module; | ||||
struct Wire; | struct Wire; | ||||
struct RackWidget; | struct RackWidget; | ||||
struct ParamWidget; | struct ParamWidget; | ||||
struct Port; | struct Port; | ||||
struct Scene; | |||||
//////////////////// | //////////////////// | ||||
// module | // module | ||||
@@ -23,7 +23,6 @@ struct Scene; | |||||
#define RACK_GRID_WIDTH 15 | #define RACK_GRID_WIDTH 15 | ||||
#define RACK_GRID_HEIGHT 380 | #define RACK_GRID_HEIGHT 380 | ||||
struct Model; | |||||
struct ModuleWidget : OpaqueWidget { | struct ModuleWidget : OpaqueWidget { | ||||
Model *model = NULL; | Model *model = NULL; | ||||
/** Owns the module pointer */ | /** Owns the module pointer */ | ||||
@@ -168,12 +167,6 @@ struct CircularShadow : TransparentWidget { | |||||
void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
}; | }; | ||||
struct LightWidget : TransparentWidget { | |||||
NVGcolor bgColor = nvgRGBf(0, 0, 0); | |||||
NVGcolor color = nvgRGBf(1, 1, 1); | |||||
void draw(NVGcontext *vg) override; | |||||
}; | |||||
struct ParamWidget : OpaqueWidget, QuantityWidget { | struct ParamWidget : OpaqueWidget, QuantityWidget { | ||||
Module *module = NULL; | Module *module = NULL; | ||||
int paramId; | int paramId; | ||||
@@ -309,6 +302,29 @@ struct SVGScrew : FramebufferWidget { | |||||
SVGScrew(); | SVGScrew(); | ||||
}; | }; | ||||
//////////////////// | |||||
// lights | |||||
//////////////////// | |||||
struct LightWidget : TransparentWidget { | |||||
NVGcolor bgColor = nvgRGBf(0, 0, 0); | |||||
NVGcolor color = nvgRGBf(1, 1, 1); | |||||
void draw(NVGcontext *vg) override; | |||||
}; | |||||
/** A LightWidget that points to a module's Light or a range of lights */ | |||||
struct ModuleLightWidget : LightWidget { | |||||
Module *module = NULL; | |||||
int lightId; | |||||
}; | |||||
/** Mixes colors based on the brightness of the module light at lightId, lightId + 1, etc */ | |||||
struct ColorLightWidget : ModuleLightWidget { | |||||
std::vector<NVGcolor> colors; | |||||
void addColor(NVGcolor c); | |||||
void step() override; | |||||
}; | |||||
//////////////////// | //////////////////// | ||||
// scene | // scene | ||||
//////////////////// | //////////////////// | ||||
@@ -337,7 +337,6 @@ struct Rogan1PWhite : Rogan1P { | |||||
struct SynthTechAlco : SVGKnob { | struct SynthTechAlco : SVGKnob { | ||||
SynthTechAlco() { | SynthTechAlco() { | ||||
box.size = Vec(45, 45); | |||||
minAngle = -0.82*M_PI; | minAngle = -0.82*M_PI; | ||||
maxAngle = 0.82*M_PI; | maxAngle = 0.82*M_PI; | ||||
setSVG(SVG::load(assetGlobal("res/ComponentLibrary/SynthTechAlco.svg"))); | setSVG(SVG::load(assetGlobal("res/ComponentLibrary/SynthTechAlco.svg"))); | ||||
@@ -423,95 +422,55 @@ struct CL1362Port : SVGPort { | |||||
// Lights | // Lights | ||||
//////////////////// | //////////////////// | ||||
struct ValueLight : LightWidget { | |||||
float *value = NULL; | |||||
virtual void setValue(float v) {} | |||||
void step() override { | |||||
if (value) | |||||
setValue(*value); | |||||
struct RedLight : ColorLightWidget { | |||||
RedLight() { | |||||
addColor(COLOR_RED); | |||||
} | } | ||||
}; | }; | ||||
struct ColorValueLight : ValueLight { | |||||
NVGcolor baseColor; | |||||
void setValue(float v) override { | |||||
v = sqrtBipolar(v); | |||||
color = baseColor; | |||||
color.a *= clampf(v, 0.0, 1.0); | |||||
struct GreenLight : ColorLightWidget { | |||||
GreenLight() { | |||||
addColor(COLOR_GREEN); | |||||
} | } | ||||
}; | }; | ||||
struct RedValueLight : ColorValueLight { | |||||
RedValueLight() { | |||||
baseColor = COLOR_RED; | |||||
struct GreenRedLight : ColorLightWidget { | |||||
GreenRedLight() { | |||||
addColor(COLOR_GREEN); | |||||
addColor(COLOR_RED); | |||||
} | } | ||||
}; | }; | ||||
struct YellowValueLight : ColorValueLight { | |||||
YellowValueLight() { | |||||
baseColor = COLOR_YELLOW; | |||||
} | |||||
}; | |||||
struct GreenValueLight : ColorValueLight { | |||||
GreenValueLight() { | |||||
baseColor = COLOR_GREEN; | |||||
} | |||||
}; | |||||
struct PolarityLight : ValueLight { | |||||
NVGcolor posColor; | |||||
NVGcolor negColor; | |||||
void setValue(float v) override { | |||||
v = sqrtBipolar(v); | |||||
color = (v >= 0.0) ? posColor : negColor; | |||||
color.a *= clampf(fabsf(v), 0.0, 1.0); | |||||
} | |||||
}; | |||||
struct GreenRedPolarityLight : PolarityLight { | |||||
GreenRedPolarityLight() { | |||||
posColor = COLOR_GREEN; | |||||
negColor = COLOR_RED; | |||||
} | |||||
}; | |||||
struct ModeValueLight : ValueLight { | |||||
std::vector<NVGcolor> colors; | |||||
void setValue(float v) override { | |||||
int mode = clampi((int)roundf(v), 0, colors.size()); | |||||
color = colors[mode]; | |||||
} | |||||
void addColor(NVGcolor color) { | |||||
colors.push_back(color); | |||||
} | |||||
}; | |||||
/** 5mm diameter */ | |||||
template <typename BASE> | template <typename BASE> | ||||
struct LargeLight : BASE { | struct LargeLight : BASE { | ||||
LargeLight() { | LargeLight() { | ||||
this->box.size = Vec(20, 20); | |||||
this->box.size = Vec(15, 15); | |||||
} | } | ||||
}; | }; | ||||
/** 3mm diameter */ | |||||
template <typename BASE> | template <typename BASE> | ||||
struct MediumLight : BASE { | struct MediumLight : BASE { | ||||
MediumLight() { | MediumLight() { | ||||
this->box.size = Vec(12, 12); | |||||
this->box.size = Vec(9, 9); | |||||
} | } | ||||
}; | }; | ||||
/** 2mm diameter */ | |||||
template <typename BASE> | template <typename BASE> | ||||
struct SmallLight : BASE { | struct SmallLight : BASE { | ||||
SmallLight() { | SmallLight() { | ||||
this->box.size = Vec(8, 8); | |||||
this->box.size = Vec(6, 6); | |||||
} | } | ||||
}; | }; | ||||
/** 1mm diameter */ | |||||
template <typename BASE> | template <typename BASE> | ||||
struct TinyLight : BASE { | struct TinyLight : BASE { | ||||
TinyLight() { | TinyLight() { | ||||
this->box.size = Vec(5, 5); | |||||
this->box.size = Vec(3, 3); | |||||
} | } | ||||
}; | }; | ||||
@@ -32,6 +32,10 @@ struct Output { | |||||
struct Light { | struct Light { | ||||
/** The square of the brightness value */ | /** The square of the brightness value */ | ||||
float value = 0.0; | float value = 0.0; | ||||
float getBrightness(); | |||||
void setBrightness(float brightness) { | |||||
value = brightness * brightness; | |||||
} | |||||
void setBrightnessSmooth(float brightness); | void setBrightnessSmooth(float brightness); | ||||
}; | }; | ||||
@@ -2,12 +2,12 @@ | |||||
#include "util.hpp" | #include "util.hpp" | ||||
#include "math.hpp" | #include "math.hpp" | ||||
#include "asset.hpp" | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "gui.hpp" | #include "gui.hpp" | ||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "components.hpp" | #include "components.hpp" | ||||
#include "asset.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -34,9 +34,16 @@ Model *createModel(std::string manufacturerSlug, std::string manufacturerName, s | |||||
return model; | return model; | ||||
} | } | ||||
template <class TParam> | |||||
template <class TScrew> | |||||
Widget *createScrew(Vec pos) { | |||||
Widget *screw = new TScrew(); | |||||
screw->box.pos = pos; | |||||
return screw; | |||||
} | |||||
template <class TParamWidget> | |||||
ParamWidget *createParam(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { | ParamWidget *createParam(Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { | ||||
ParamWidget *param = new TParam(); | |||||
ParamWidget *param = new TParamWidget(); | |||||
param->box.pos = pos; | param->box.pos = pos; | ||||
param->module = module; | param->module = module; | ||||
param->paramId = paramId; | param->paramId = paramId; | ||||
@@ -65,18 +72,12 @@ Port *createOutput(Vec pos, Module *module, int outputId) { | |||||
return port; | return port; | ||||
} | } | ||||
template <class TScrew> | |||||
Widget *createScrew(Vec pos) { | |||||
Widget *screw = new TScrew(); | |||||
screw->box.pos = pos; | |||||
return screw; | |||||
} | |||||
template <class TLight> | |||||
ValueLight *createValueLight(Vec pos, float *value) { | |||||
ValueLight *light = new TLight(); | |||||
template<class TModuleLightWidget> | |||||
ModuleLightWidget *createLight(Vec pos, Module *module, int lightId) { | |||||
ModuleLightWidget *light = new TModuleLightWidget(); | |||||
light->box.pos = pos; | light->box.pos = pos; | ||||
light->value = value; | |||||
light->module = module; | |||||
light->lightId = lightId; | |||||
return light; | return light; | ||||
} | } | ||||
@@ -0,0 +1,24 @@ | |||||
#include "app.hpp" | |||||
#include "engine.hpp" | |||||
namespace rack { | |||||
void ColorLightWidget::addColor(NVGcolor c) { | |||||
colors.push_back(c); | |||||
} | |||||
void ColorLightWidget::step() { | |||||
color = nvgRGBf(0, 0, 0); | |||||
for (int i = 0; i < (int)colors.size(); i++) { | |||||
NVGcolor c = colors[i]; | |||||
float brightness = module->lights[lightId + i].getBrightness(); | |||||
color.r += c.r * brightness; | |||||
color.g += c.g * brightness; | |||||
color.b += c.b * brightness; | |||||
} | |||||
} | |||||
} // namespace rack |
@@ -87,10 +87,10 @@ WireWidget::WireWidget() { | |||||
lastWireColorId = (lastWireColorId + 1) % LENGTHOF(wireColors); | lastWireColorId = (lastWireColorId + 1) % LENGTHOF(wireColors); | ||||
color = wireColors[lastWireColorId]; | color = wireColors[lastWireColorId]; | ||||
inputLight = construct<PolarityLight>(&PolarityLight::posColor, COLOR_GREEN, &PolarityLight::negColor, COLOR_RED); | |||||
outputLight = construct<PolarityLight>(&PolarityLight::posColor, COLOR_GREEN, &PolarityLight::negColor, COLOR_RED); | |||||
addChild(inputLight); | |||||
addChild(outputLight); | |||||
// inputLight = construct<PolarityLight>(&PolarityLight::posColor, COLOR_GREEN, &PolarityLight::negColor, COLOR_RED); | |||||
// outputLight = construct<PolarityLight>(&PolarityLight::posColor, COLOR_GREEN, &PolarityLight::negColor, COLOR_RED); | |||||
// addChild(inputLight); | |||||
// addChild(outputLight); | |||||
} | } | ||||
WireWidget::~WireWidget() { | WireWidget::~WireWidget() { | ||||
@@ -166,6 +166,7 @@ void WireWidget::drawPlugs(NVGcontext *vg) { | |||||
drawPlug(vg, inputPos, color); | drawPlug(vg, inputPos, color); | ||||
// Draw plug light | // Draw plug light | ||||
/* | |||||
if (gToolbar->plugLightButton->value > 0.0) { | if (gToolbar->plugLightButton->value > 0.0) { | ||||
if (wire) { | if (wire) { | ||||
Output &output = wire->outputModule->outputs[wire->outputId]; | Output &output = wire->outputModule->outputs[wire->outputId]; | ||||
@@ -188,6 +189,7 @@ void WireWidget::drawPlugs(NVGcontext *vg) { | |||||
outputLight->visible = false; | outputLight->visible = false; | ||||
inputLight->visible = false; | inputLight->visible = false; | ||||
} | } | ||||
*/ | |||||
Widget::draw(vg); | Widget::draw(vg); | ||||
} | } | ||||
@@ -18,6 +18,9 @@ struct MIDICCToCVInterface : MidiIO, Module { | |||||
enum OutputIds { | enum OutputIds { | ||||
NUM_OUTPUTS = 16 | NUM_OUTPUTS = 16 | ||||
}; | }; | ||||
enum LightIds { | |||||
NUM_LIGHTS = 16 | |||||
}; | |||||
int cc[NUM_OUTPUTS]; | int cc[NUM_OUTPUTS]; | ||||
int ccNum[NUM_OUTPUTS]; | int ccNum[NUM_OUTPUTS]; | ||||
@@ -25,10 +28,9 @@ struct MIDICCToCVInterface : MidiIO, Module { | |||||
bool ccSyncFirst[NUM_OUTPUTS]; | bool ccSyncFirst[NUM_OUTPUTS]; | ||||
bool ccNumInited[NUM_OUTPUTS]; | bool ccNumInited[NUM_OUTPUTS]; | ||||
bool onFocus[NUM_OUTPUTS]; | bool onFocus[NUM_OUTPUTS]; | ||||
float lights[NUM_OUTPUTS]; | |||||
MIDICCToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||||
MIDICCToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | for (int i = 0; i < NUM_OUTPUTS; i++) { | ||||
cc[i] = 0; | cc[i] = 0; | ||||
ccNum[i] = i; | ccNum[i] = i; | ||||
@@ -97,7 +99,7 @@ void MIDICCToCVInterface::step() { | |||||
for (int i = 0; i < NUM_OUTPUTS; i++) { | for (int i = 0; i < NUM_OUTPUTS; i++) { | ||||
lights[i] = ccSync[i] / 127.0; | |||||
lights[i].setBrightness(ccSync[i] / 127.0); | |||||
outputs[i].value = cc[i] / 127.0 * 10.0; | outputs[i].value = cc[i] / 127.0 * 10.0; | ||||
} | } | ||||
@@ -294,8 +296,7 @@ MIDICCToCVWidget::MIDICCToCVWidget() { | |||||
yPos += labelHeight + margin; | yPos += labelHeight + margin; | ||||
addOutput(createOutput<PJ3410Port>(Vec((i % 4) * (63) + 10, yPos + 5), module, i)); | addOutput(createOutput<PJ3410Port>(Vec((i % 4) * (63) + 10, yPos + 5), module, i)); | ||||
addChild(createValueLight<SmallLight<RedValueLight>>(Vec((i % 4) * (63) + 32, yPos + 5), | |||||
&module->lights[i])); | |||||
addChild(createLight<SmallLight<RedLight>>(Vec((i % 4) * (63) + 32, yPos + 5), module, i)); | |||||
if ((i + 1) % 4 == 0) { | if ((i + 1) % 4 == 0) { | ||||
yPos += 47 + margin; | yPos += 47 + margin; | ||||
@@ -26,6 +26,10 @@ struct MIDIToCVInterface : MidiIO, Module { | |||||
CHANNEL_AFTERTOUCH_OUTPUT, | CHANNEL_AFTERTOUCH_OUTPUT, | ||||
NUM_OUTPUTS | NUM_OUTPUTS | ||||
}; | }; | ||||
enum LightIds { | |||||
RESET_LIGHT, | |||||
NUM_LIGHTS | |||||
}; | |||||
std::list<int> notes; | std::list<int> notes; | ||||
bool pedal = false; | bool pedal = false; | ||||
@@ -38,9 +42,8 @@ struct MIDIToCVInterface : MidiIO, Module { | |||||
bool retriggered = false; | bool retriggered = false; | ||||
SchmittTrigger resetTrigger; | SchmittTrigger resetTrigger; | ||||
float resetLight = 0.0; | |||||
MIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||||
MIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
} | } | ||||
@@ -78,14 +81,11 @@ void MIDIToCVInterface::resetMidi() { | |||||
pitchWheel = 64; | pitchWheel = 64; | ||||
afterTouch = 0; | afterTouch = 0; | ||||
vel = 0; | vel = 0; | ||||
resetLight = 1.0; | |||||
outputs[GATE_OUTPUT].value = 0.0; | outputs[GATE_OUTPUT].value = 0.0; | ||||
notes.clear(); | notes.clear(); | ||||
} | } | ||||
void MIDIToCVInterface::step() { | void MIDIToCVInterface::step() { | ||||
float sampleRate = engineGetSampleRate(); | |||||
if (isPortOpen()) { | if (isPortOpen()) { | ||||
std::vector<unsigned char> message; | std::vector<unsigned char> message; | ||||
@@ -109,10 +109,7 @@ void MIDIToCVInterface::step() { | |||||
return; | return; | ||||
} | } | ||||
if (resetLight > 0) { | |||||
resetLight -= resetLight / 0.55 / sampleRate; // fade out light | |||||
} | |||||
lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / 0.55 / engineGetSampleRate(); // fade out light | |||||
outputs[GATE_OUTPUT].value = gate ? 10.0 : 0.0; | outputs[GATE_OUTPUT].value = gate ? 10.0 : 0.0; | ||||
outputs[MOD_OUTPUT].value = mod / 127.0 * 10.0; | outputs[MOD_OUTPUT].value = mod / 127.0 * 10.0; | ||||
@@ -228,7 +225,7 @@ MidiToCVWidget::MidiToCVWidget() { | |||||
} | } | ||||
addParam(createParam<LEDButton>(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0)); | addParam(createParam<LEDButton>(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0)); | ||||
addChild(createValueLight<SmallLight<RedValueLight>>(Vec(7 * 15 + 5, labelHeight + 5), &module->resetLight)); | |||||
addChild(createLight<SmallLight<RedLight>>(Vec(7 * 15 + 5, labelHeight + 5), module, MIDIToCVInterface::RESET_LIGHT)); | |||||
{ | { | ||||
Label *label = new Label(); | Label *label = new Label(); | ||||
label->box.pos = Vec(margin, yPos); | label->box.pos = Vec(margin, yPos); | ||||
@@ -260,7 +257,7 @@ MidiToCVWidget::MidiToCVWidget() { | |||||
} | } | ||||
std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel", | std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel", | ||||
"Aftertouch"}; | |||||
"Aftertouch"}; | |||||
for (int i = 0; i < MIDIToCVInterface::NUM_OUTPUTS; i++) { | for (int i = 0; i < MIDIToCVInterface::NUM_OUTPUTS; i++) { | ||||
Label *label = new Label(); | Label *label = new Label(); | ||||
@@ -27,6 +27,10 @@ struct QuadMIDIToCVInterface : MidiIO, Module { | |||||
AT_OUTPUT = 12, | AT_OUTPUT = 12, | ||||
NUM_OUTPUTS = 16 | NUM_OUTPUTS = 16 | ||||
}; | }; | ||||
enum LightIds { | |||||
RESET_LIGHT, | |||||
NUM_LIGHTS | |||||
}; | |||||
enum Modes { | enum Modes { | ||||
ROTATE, | ROTATE, | ||||
@@ -46,9 +50,8 @@ struct QuadMIDIToCVInterface : MidiIO, Module { | |||||
std::list<int> open; | std::list<int> open; | ||||
SchmittTrigger resetTrigger; | SchmittTrigger resetTrigger; | ||||
float resetLight = 0.0; | |||||
QuadMIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { | |||||
QuadMIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
} | } | ||||
@@ -89,13 +92,10 @@ void QuadMIDIToCVInterface::resetMidi() { | |||||
open.clear(); | open.clear(); | ||||
pedal = false; | pedal = false; | ||||
resetLight = 1.0; | |||||
lights[RESET_LIGHT].value = 1.0; | |||||
} | } | ||||
void QuadMIDIToCVInterface::step() { | void QuadMIDIToCVInterface::step() { | ||||
float sampleRate = engineGetSampleRate(); | |||||
if (isPortOpen()) { | if (isPortOpen()) { | ||||
std::vector<unsigned char> message; | std::vector<unsigned char> message; | ||||
int msgsProcessed = 0; | int msgsProcessed = 0; | ||||
@@ -124,10 +124,7 @@ void QuadMIDIToCVInterface::step() { | |||||
return; | return; | ||||
} | } | ||||
if (resetLight > 0) { | |||||
resetLight -= resetLight / 0.55 / sampleRate; // fade out light | |||||
} | |||||
lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / 0.55 / engineGetSampleRate(); // fade out light | |||||
} | } | ||||
@@ -304,7 +301,7 @@ QuadMidiToCVWidget::QuadMidiToCVWidget() { | |||||
addParam(createParam<LEDButton>(Vec(12 * 15, labelHeight), module, QuadMIDIToCVInterface::RESET_PARAM, 0.0, 1.0, | addParam(createParam<LEDButton>(Vec(12 * 15, labelHeight), module, QuadMIDIToCVInterface::RESET_PARAM, 0.0, 1.0, | ||||
0.0)); | 0.0)); | ||||
addChild(createValueLight<SmallLight<RedValueLight>>(Vec(12 * 15 + 5, labelHeight + 5), &module->resetLight)); | |||||
addChild(createLight<SmallLight<RedLight>>(Vec(12 * 15 + 5, labelHeight + 5), module, QuadMIDIToCVInterface::RESET_LIGHT)); | |||||
{ | { | ||||
Label *label = new Label(); | Label *label = new Label(); | ||||
label->box.pos = Vec(margin, yPos); | label->box.pos = Vec(margin, yPos); | ||||
@@ -33,8 +33,12 @@ static int smoothParamId; | |||||
static float smoothValue; | static float smoothValue; | ||||
float Light::getBrightness() { | |||||
return sqrtf(value); | |||||
} | |||||
void Light::setBrightnessSmooth(float brightness) { | void Light::setBrightnessSmooth(float brightness) { | ||||
value += (powf(brightness, 2) - value) / sampleRate * 60.0; | |||||
value += (brightness * brightness - value) / sampleRate * 60.0; | |||||
} | } | ||||