| @@ -7,13 +7,13 @@ | |||
| namespace rack { | |||
| struct Model; | |||
| struct Module; | |||
| struct Wire; | |||
| struct RackWidget; | |||
| struct ParamWidget; | |||
| struct Port; | |||
| struct Scene; | |||
| //////////////////// | |||
| // module | |||
| @@ -23,7 +23,6 @@ struct Scene; | |||
| #define RACK_GRID_WIDTH 15 | |||
| #define RACK_GRID_HEIGHT 380 | |||
| struct Model; | |||
| struct ModuleWidget : OpaqueWidget { | |||
| Model *model = NULL; | |||
| /** Owns the module pointer */ | |||
| @@ -168,12 +167,6 @@ struct CircularShadow : TransparentWidget { | |||
| 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 { | |||
| Module *module = NULL; | |||
| int paramId; | |||
| @@ -309,6 +302,29 @@ struct SVGScrew : FramebufferWidget { | |||
| 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 | |||
| //////////////////// | |||
| @@ -422,95 +422,55 @@ struct CL1362Port : SVGPort { | |||
| // 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> | |||
| struct LargeLight : BASE { | |||
| LargeLight() { | |||
| this->box.size = Vec(20, 20); | |||
| this->box.size = Vec(15, 15); | |||
| } | |||
| }; | |||
| /** 3mm diameter */ | |||
| template <typename BASE> | |||
| struct MediumLight : BASE { | |||
| MediumLight() { | |||
| this->box.size = Vec(12, 12); | |||
| this->box.size = Vec(9, 9); | |||
| } | |||
| }; | |||
| /** 2mm diameter */ | |||
| template <typename BASE> | |||
| struct SmallLight : BASE { | |||
| SmallLight() { | |||
| this->box.size = Vec(8, 8); | |||
| this->box.size = Vec(6, 6); | |||
| } | |||
| }; | |||
| /** 1mm diameter */ | |||
| template <typename BASE> | |||
| struct TinyLight : BASE { | |||
| TinyLight() { | |||
| this->box.size = Vec(5, 5); | |||
| this->box.size = Vec(3, 3); | |||
| } | |||
| }; | |||
| @@ -32,6 +32,7 @@ struct Output { | |||
| struct Light { | |||
| /** The square of the brightness value */ | |||
| float value = 0.0; | |||
| float getBrightness(); | |||
| void setBrightness(float brightness) { | |||
| value = brightness * brightness; | |||
| } | |||
| @@ -34,9 +34,16 @@ Model *createModel(std::string manufacturerSlug, std::string manufacturerName, s | |||
| 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 *param = new TParam(); | |||
| ParamWidget *param = new TParamWidget(); | |||
| param->box.pos = pos; | |||
| param->module = module; | |||
| param->paramId = paramId; | |||
| @@ -65,27 +72,12 @@ Port *createOutput(Vec pos, Module *module, int outputId) { | |||
| 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(); | |||
| light->box.pos = pos; | |||
| light->value = value; | |||
| return light; | |||
| } | |||
| /** Polyfill for future LightWidget */ | |||
| template <class TLight> | |||
| ValueLight *createValueLight(Vec pos, Module *module, int lightId) { | |||
| ValueLight *light = new TLight(); | |||
| template<class TModuleLightWidget> | |||
| ModuleLightWidget *createLight(Vec pos, Module *module, int lightId) { | |||
| ModuleLightWidget *light = new TModuleLightWidget(); | |||
| light->box.pos = pos; | |||
| light->value = &module->lights[lightId].value; | |||
| light->module = module; | |||
| light->lightId = lightId; | |||
| 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); | |||
| 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() { | |||
| @@ -166,6 +166,7 @@ void WireWidget::drawPlugs(NVGcontext *vg) { | |||
| drawPlug(vg, inputPos, color); | |||
| // Draw plug light | |||
| /* | |||
| if (gToolbar->plugLightButton->value > 0.0) { | |||
| if (wire) { | |||
| Output &output = wire->outputModule->outputs[wire->outputId]; | |||
| @@ -188,6 +189,7 @@ void WireWidget::drawPlugs(NVGcontext *vg) { | |||
| outputLight->visible = false; | |||
| inputLight->visible = false; | |||
| } | |||
| */ | |||
| Widget::draw(vg); | |||
| } | |||
| @@ -18,6 +18,9 @@ struct MIDICCToCVInterface : MidiIO, Module { | |||
| enum OutputIds { | |||
| NUM_OUTPUTS = 16 | |||
| }; | |||
| enum LightIds { | |||
| NUM_LIGHTS = 16 | |||
| }; | |||
| int cc[NUM_OUTPUTS]; | |||
| int ccNum[NUM_OUTPUTS]; | |||
| @@ -25,10 +28,9 @@ struct MIDICCToCVInterface : MidiIO, Module { | |||
| bool ccSyncFirst[NUM_OUTPUTS]; | |||
| bool ccNumInited[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++) { | |||
| cc[i] = 0; | |||
| ccNum[i] = i; | |||
| @@ -97,7 +99,7 @@ void MIDICCToCVInterface::step() { | |||
| 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; | |||
| } | |||
| @@ -294,8 +296,7 @@ MIDICCToCVWidget::MIDICCToCVWidget() { | |||
| yPos += labelHeight + margin; | |||
| 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) { | |||
| yPos += 47 + margin; | |||
| @@ -26,6 +26,10 @@ struct MIDIToCVInterface : MidiIO, Module { | |||
| CHANNEL_AFTERTOUCH_OUTPUT, | |||
| NUM_OUTPUTS | |||
| }; | |||
| enum LightIds { | |||
| RESET_LIGHT, | |||
| NUM_LIGHTS | |||
| }; | |||
| std::list<int> notes; | |||
| bool pedal = false; | |||
| @@ -38,9 +42,8 @@ struct MIDIToCVInterface : MidiIO, Module { | |||
| bool retriggered = false; | |||
| 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; | |||
| afterTouch = 0; | |||
| vel = 0; | |||
| resetLight = 1.0; | |||
| outputs[GATE_OUTPUT].value = 0.0; | |||
| notes.clear(); | |||
| } | |||
| void MIDIToCVInterface::step() { | |||
| static float sampleRate = engineGetSampleRate(); | |||
| if (isPortOpen()) { | |||
| std::vector<unsigned char> message; | |||
| @@ -109,10 +109,7 @@ void MIDIToCVInterface::step() { | |||
| 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[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)); | |||
| 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->box.pos = Vec(margin, yPos); | |||
| @@ -28,6 +28,10 @@ struct QuadMIDIToCVInterface : MidiIO, Module { | |||
| AT_OUTPUT = 12, | |||
| NUM_OUTPUTS = 16 | |||
| }; | |||
| enum LightIds { | |||
| RESET_LIGHT, | |||
| NUM_LIGHTS | |||
| }; | |||
| enum Modes { | |||
| ROTATE, | |||
| @@ -47,9 +51,8 @@ struct QuadMIDIToCVInterface : MidiIO, Module { | |||
| std::list<int> open; | |||
| 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) { | |||
| } | |||
| @@ -90,11 +93,10 @@ void QuadMIDIToCVInterface::resetMidi() { | |||
| open.clear(); | |||
| pedal = false; | |||
| resetLight = 1.0; | |||
| lights[RESET_LIGHT].value = 1.0; | |||
| } | |||
| void QuadMIDIToCVInterface::step() { | |||
| static float sampleRate = engineGetSampleRate(); | |||
| static int msgsProcessed = 0; | |||
| if (isPortOpen()) { | |||
| @@ -125,10 +127,7 @@ void QuadMIDIToCVInterface::step() { | |||
| 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 | |||
| } | |||
| @@ -307,7 +306,7 @@ QuadMidiToCVWidget::QuadMidiToCVWidget() { | |||
| addParam(createParam<LEDButton>(Vec(12 * 15, labelHeight), module, QuadMIDIToCVInterface::RESET_PARAM, 0.0, 1.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->box.pos = Vec(margin, yPos); | |||
| @@ -33,6 +33,10 @@ static int smoothParamId; | |||
| static float smoothValue; | |||
| float Light::getBrightness() { | |||
| return sqrtf(value); | |||
| } | |||
| void Light::setBrightnessSmooth(float brightness) { | |||
| value += (brightness * brightness - value) / sampleRate * 60.0; | |||
| } | |||