computerscare-vcv-modules

computerscare modules for VCV Rack
Log | Files | Refs

commit fa913abf749b617a8398a32e812e245c0093b5ba
parent ff852a76435d67afb8a8ea9a0dcce1a451c91c66
Author: Adam M <aemalone@gmail.com>
Date:   Sun,  3 Jan 2021 21:15:11 -0600

Giant display of scrubbed frame when zelecting sero

Diffstat:
Msrc/Computerscare.hpp | 28++++++++++++++--------------
Msrc/ComputerscareBlank.cpp | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/ComputerscareBlankExpander.cpp | 58+++++++++++++++++++++++++++++++++++++++++++---------------
Asrc/CustomBlankFunctions.hpp | 6++++++
Msrc/MenuParams.hpp | 2+-
5 files changed, 169 insertions(+), 61 deletions(-)

diff --git a/src/Computerscare.hpp b/src/Computerscare.hpp @@ -53,7 +53,7 @@ static const NVGcolor COLOR_COMPUTERSCARE_YELLOW = nvgRGB(0xE4, 0xC4, 0x21); static const NVGcolor COLOR_COMPUTERSCARE_BLUE = nvgRGB(0x24, 0x44, 0xC1); static const NVGcolor COLOR_COMPUTERSCARE_PINK = nvgRGB(0xAA, 0x18, 0x31); static const NVGcolor COLOR_COMPUTERSCARE_TRANSPARENT = nvgRGBA(0x00, 0x00, 0x00, 0x00); -static const NVGcolor BLACK=nvgRGB(0x00,0x00,0x00); +static const NVGcolor BLACK = nvgRGB(0x00, 0x00, 0x00); namespace rack { @@ -113,7 +113,7 @@ struct InputBlockBackground : TransparentWidget { nvgBeginPath(args.vg); nvgRect(args.vg, box.pos.x, box.pos.y, box.size.x, box.size.y); nvgStrokeColor(args.vg, COLOR_COMPUTERSCARE_BLUE); - nvgStrokeWidth(args.vg,2.5); + nvgStrokeWidth(args.vg, 2.5); nvgFillColor(args.vg, COLOR_COMPUTERSCARE_LIGHT_GREEN); nvgFill(args.vg); Widget::draw(args); @@ -128,15 +128,15 @@ struct IsoButton : SvgSwitch { } }; struct SmallIsoButton : app::SvgSwitch { - bool disabled=true; - bool lastDisabled=false; + bool disabled = true; + bool lastDisabled = false; std::vector<std::shared_ptr<Svg>> enabledFrames; std::vector<std::shared_ptr<Svg>> disabledFrames; SmallIsoButton() { enabledFrames.push_back(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-iso-button-small-up.svg"))); enabledFrames.push_back(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-iso-button-small-down.svg"))); - + disabledFrames.push_back(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-iso-button-small-up-grey.svg"))); disabledFrames.push_back(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-iso-button-small-down-grey.svg"))); @@ -148,16 +148,16 @@ struct SmallIsoButton : app::SvgSwitch { void step() override { if (disabled != lastDisabled) { - if(disabled) { - frames[0]=disabledFrames[0]; - frames[1]=disabledFrames[1]; + if (disabled) { + frames[0] = disabledFrames[0]; + frames[1] = disabledFrames[1]; } else { - frames[0]=enabledFrames[0]; - frames[1]=enabledFrames[1]; + frames[0] = enabledFrames[0]; + frames[1] = enabledFrames[1]; } onChange(*(new event::Change())); - fb->dirty=true; + fb->dirty = true; dirtyValue = -20.f; lastDisabled = disabled; @@ -383,14 +383,14 @@ struct ScrambleKnob : RoundKnob { }; struct ScrambleSnapKnob : RoundKnob { ScrambleSnapKnob() { - snap=true; + snap = true; shadow->opacity = 0.f; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-scramble-knob.svg"))); } }; struct ScrambleSnapKnobNoRandom : RoundKnob { ScrambleSnapKnobNoRandom() { - snap=true; + snap = true; shadow->opacity = 0.f; setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-scramble-knob.svg"))); } @@ -484,7 +484,7 @@ struct SmallLetterDisplay : Widget { std::string defaultFontPath = "res/Oswald-Regular.ttf"; NVGcolor baseColor = COLOR_COMPUTERSCARE_TRANSPARENT; NVGcolor textColor = nvgRGB(0x10, 0x10, 0x00); - Vec textOffset = Vec(0,0); + Vec textOffset = Vec(0, 0); float letterSpacing = 2.5; int textAlign = 1; diff --git a/src/ComputerscareBlank.cpp b/src/ComputerscareBlank.cpp @@ -1,6 +1,8 @@ #include "Computerscare.hpp" #include "ComputerscareResizableHandle.hpp" #include "animatedGif.hpp" +#include "CustomBlankFunctions.hpp" + #include <osdialog.h> #include <iostream> #include <fstream> @@ -10,7 +12,6 @@ #define FONT_SIZE 13 -struct ComputerscareBlank; struct ComputerscareBlank : ComputerscareMenuParamModule { bool loading = true; @@ -43,6 +44,11 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { int samplesDelay = 10000; int speed = 100000; int imageStatus = 0; + bool scrubbing = false; + int scrubFrame = 0; + + int pingPongDirection = 1; + /* uninitialized: 0 gif: 1 @@ -59,7 +65,7 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { float leftMessages[2][8] = {}; - int pingPongDirection = 1; + float speedFactor = 1.f; @@ -121,6 +127,7 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { leftExpander.producerMessage = leftMessages[0]; leftExpander.consumerMessage = leftMessages[1]; + } void process(const ProcessArgs &args) override { if (imageStatus == 1) { @@ -144,6 +151,10 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { zeroOffset = messageFromExpander[7]; + scrubbing = messageFromExpander[8]; + + updateScrubFrame(); + if (clockConnected) { bool clockTriggered = clockTrigger.process(messageFromExpander[2]); if (clockMode == 0) { @@ -199,7 +210,11 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { } } - + void updateScrubFrame() { + if (ready) { + scrubFrame = mapBlankFrameOffset(zeroOffset, numFrames); + } + } void onReset() override { zoomX = 1; @@ -338,7 +353,12 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { prevFrame(); } else if (animationMode == 2) { - pingPongDirection == 1 ? nextFrame() : prevFrame(); + if (pingPongDirection == 1) { + + nextFrame(); + } else { + prevFrame(); + } } else if (animationMode == 4 ) { goToRandomFrame(); @@ -348,17 +368,23 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { else { prevFrame(); } - if (currentFrame == numFrames - 1) { - if (animationMode == 2 ) { - pingPongDirection = -1; + if (animationMode == 2) { + //DEBUG("PRE ping current:%i,direction:%i", currentFrame, pingPongDirection); + if (pingPongDirection == 1) { + if (currentFrame == numFrames - 1) { + pingPongDirection = -1; + } + } + else { + if (currentFrame == 0) { + pingPongDirection = 1; + } } } + if (currentFrame == 0) { int eb = params[END_BEHAVIOR].getValue(); - if (animationMode == 2) { - pingPongDirection = 1; - } if (eb == 3 ) { loadRandomGif(); } @@ -379,10 +405,10 @@ struct ComputerscareBlank : ComputerscareMenuParamModule { goToFrame(currentFrame - 1); } void goToFrame(int frameNum) { - if (numFrames) { + if (numFrames && ready) { sampleCounter = 0; currentFrame = frameNum; - mappedFrame = (currentFrame + ((int)floor(zeroOffset * numFrames))+numFrames) % numFrames; + mappedFrame = (currentFrame + mapBlankFrameOffset(zeroOffset, numFrames)) % numFrames; currentFrame += numFrames; currentFrame %= numFrames; setCurrentFrameDelayFromTable(); @@ -670,8 +696,47 @@ struct PNGDisplay : TransparentWidget { if (blankModule && blankModule->loadedJSON) { if (blankModule->mappedFrame != currentFrame) { currentFrame = blankModule->mappedFrame; - } + if (blankModule->scrubbing) { + currentFrame = blankModule->scrubFrame; + } + } + TransparentWidget::step(); + } +}; + +struct GiantFrameDisplay : TransparentWidget { + ComputerscareBlank *module; + SmallLetterDisplay *description; + SmallLetterDisplay *frameDisplay; + GiantFrameDisplay() { + box.size = Vec(200,380); + + description = new SmallLetterDisplay(); + description->value = "Frame Zero, for EOC output and reset input"; + description->fontSize = 24; + description->breakRowWidth = 200.f; + description->box.pos.y = box.size.y - 130; + + + frameDisplay = new SmallLetterDisplay(); + frameDisplay->fontSize = 90; + frameDisplay->box.size = Vec(300, 120); + frameDisplay->textOffset = Vec(0, 50); + frameDisplay->box.pos.y = box.size.y - 200; + frameDisplay->breakRowWidth = 200.f; + frameDisplay->baseColor = nvgRGBAf(0.8, 0.8, 0.8, 0.7); + + + + addChild(frameDisplay); + addChild(description); + TransparentWidget(); + } + void step() { + if (module) { + visible = module->scrubbing; + frameDisplay->value = string::f("%i / %i", module->scrubFrame + 1, module->numFrames); } TransparentWidget::step(); } @@ -720,15 +785,41 @@ struct ComputerscareBlankWidget : MenuParamModuleWidget { addChild(leftHandle); addChild(rightHandle); + frameDisplay = new GiantFrameDisplay(); + frameDisplay->module = blankModule; + addChild(frameDisplay); + } void appendContextMenu(Menu* menu) override { ComputerscareBlank* blank = dynamic_cast<ComputerscareBlank*>(this->blankModule); + + Strongbipper *modeMenu = new Strongbipper(); + modeMenu->text = "Animation Mode"; + modeMenu->rightText = RIGHT_ARROW; + modeMenu->param = blankModule->paramQuantities[ComputerscareBlank::ANIMATION_MODE]; + modeMenu->options = blankModule->animationModeDescriptions; + + + + + + Strongbipper *endMenu = new Strongbipper(); + endMenu->text = "Animation End Behavior"; + endMenu->rightText = RIGHT_ARROW; + endMenu->param = blankModule->paramQuantities[ComputerscareBlank::END_BEHAVIOR]; + endMenu->options = blankModule->endBehaviorDescriptions; + + + menu->addChild(new MenuEntry); //menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Keyboard Controls:")); + menu->addChild(modeMenu); + menu->addChild(endMenu); + KeyboardControlChildMenu *kbMenu = new KeyboardControlChildMenu(); kbMenu->text = "Keyboard Controls"; kbMenu->rightText = RIGHT_ARROW; @@ -778,23 +869,6 @@ struct ComputerscareBlankWidget : MenuParamModuleWidget { - Strongbipper *modeMenu = new Strongbipper(); - modeMenu->text = "Animation Mode"; - modeMenu->rightText = RIGHT_ARROW; - modeMenu->param = blankModule->paramQuantities[ComputerscareBlank::ANIMATION_MODE]; - modeMenu->options = blankModule->animationModeDescriptions; - - menu->addChild(modeMenu); - - - - Strongbipper *endMenu = new Strongbipper(); - endMenu->text = "Animation End Behavior"; - endMenu->rightText = RIGHT_ARROW; - endMenu->param = blankModule->paramQuantities[ComputerscareBlank::END_BEHAVIOR]; - endMenu->options = blankModule->endBehaviorDescriptions; - - menu->addChild(endMenu); @@ -920,7 +994,7 @@ struct ComputerscareBlankWidget : MenuParamModuleWidget { TransparentWidget *display; ComputerscareResizeHandle *leftHandle; ComputerscareResizeHandle *rightHandle; - SmallLetterDisplay* smallLetterDisplay; + GiantFrameDisplay* frameDisplay; }; diff --git a/src/ComputerscareBlankExpander.cpp b/src/ComputerscareBlankExpander.cpp @@ -1,24 +1,29 @@ #include "Computerscare.hpp" +#include "CustomBlankFunctions.hpp" struct ComputerscareBlankExpander; - struct FrameOffsetParam : ParamQuantity { - ComputerscareBlankExpander* module; - int numFrames = -1; - void setNumFrames(int num) { numFrames = num; } - std::string getDisplayValueString() override { - //return &module->params[paramId]; - float val = getValue(); - return string::f("%i", 1+((int) floor(val * numFrames )) % numFrames/*module->getFrameOffset()*/ ); - //return "Frame " +((std:: string)val);//+ ((int) floor(val * module->numFrames * 0.999)) % module->numFrames; - } - }; + +struct FrameOffsetParam : ParamQuantity { + ComputerscareBlankExpander* module; + int numFrames = -1; + void setNumFrames(int num) { numFrames = num; } + std::string getDisplayValueString() override { + //return &module->params[paramId]; + float val = getValue(); + return string::f("%i", 1 + mapBlankFrameOffset(val,numFrames)); + } +}; + + struct ComputerscareBlankExpander : Module { - float rightMessages[2][8] = {}; + float rightMessages[2][10] = {}; bool isConnected = false; float lastFrame = -1; int numFrames = 1; + bool scrubbing = false; + enum ParamIds { CLOCK_MODE, @@ -83,7 +88,7 @@ struct ComputerscareBlankExpander : Module { float currentFrame = messageFromMother[0]; int newNumFrames = messageFromMother[1]; - if(newNumFrames != numFrames) { + if (newNumFrames != numFrames) { numFrames = newNumFrames; frameOffsetQuantity->setNumFrames(numFrames); } @@ -111,6 +116,9 @@ struct ComputerscareBlankExpander : Module { messageToSendToMother[7] = params[ZERO_OFFSET].getValue(); + messageToSendToMother[8] = scrubbing; + + outputs[EOC_OUTPUT].setVoltage(eocPulse.process(args.sampleTime) ? 10.f : 0.f); outputs[EACH_FRAME_OUTPUT].setVoltage(eachFramePulse.process(args.sampleTime) ? 10.f : 0.f); @@ -122,6 +130,23 @@ struct ComputerscareBlankExpander : Module { // No mother module is connected. } } + void setScrubbing(bool scrub) { + scrubbing = scrub; + } +}; +struct FrameScrubKnob : SmallKnob { + ComputerscareBlankExpander* module; + void onDragStart(const event::DragStart& e) override { + module->setScrubbing(true); + SmallKnob::onDragStart(e); + } + void onDragEnd(const event::DragEnd& e) override { + module->setScrubbing(false); + SmallKnob::onDragEnd(e); + } + void onDragMove(const event::DragMove& e) override { + SmallKnob::onDragMove(e); + }; }; struct ClockModeButton : app::SvgSwitch { ClockModeButton() { @@ -158,13 +183,16 @@ struct ComputerscareBlankExpanderWidget : ModuleWidget { addOutput(createOutput<PointingUpPentagonPort>(Vec(2, outStartY), module, ComputerscareBlankExpander::EACH_FRAME_OUTPUT)); + frameOffsetKnob = createParam<FrameScrubKnob>(Vec(6, outStartY + dY), module, ComputerscareBlankExpander::ZERO_OFFSET); + frameOffsetKnob->module = module; - addParam(createParam<SmallKnob>(Vec(4, outStartY + dY), module, ComputerscareBlankExpander::ZERO_OFFSET)); - addOutput(createOutput<PointingUpPentagonPort>(Vec(2, outStartY + dY * 1.5), module, ComputerscareBlankExpander::EOC_OUTPUT)); + addParam(frameOffsetKnob); + addOutput(createOutput<PointingUpPentagonPort>(Vec(2, outStartY + dY * 1.6), module, ComputerscareBlankExpander::EOC_OUTPUT)); } void step() { ModuleWidget::step(); } + FrameScrubKnob* frameOffsetKnob; }; Model *modelComputerscareBlankExpander = createModel<ComputerscareBlankExpander, ComputerscareBlankExpanderWidget>("computerscare-blank-expander"); diff --git a/src/CustomBlankFunctions.hpp b/src/CustomBlankFunctions.hpp @@ -0,0 +1,5 @@ +#pragma once + +inline int mapBlankFrameOffset(float uniformVal,int numFrames) { + return numFrames > 0 ? ((int) floor(uniformVal * numFrames )) % numFrames : 0; + } +\ No newline at end of file diff --git a/src/MenuParams.hpp b/src/MenuParams.hpp @@ -69,7 +69,7 @@ struct MenuParam : MenuEntry { } speedParam->paramQuantity = param; speedParam->box.pos = Vec(controlRightMargin, 0); - box.size.y = 38; + box.size.y = 32; johnLabel = construct<MenuLabel>(&MenuLabel::text, param->getLabel()); johnLabel->box.pos = Vec(speedParam->box.size.x + controlRightMargin * 2, 0);