diff --git a/res/BouncyBall.svg b/res/BouncyBall.svg new file mode 100644 index 0000000..f8daf83 --- /dev/null +++ b/res/BouncyBall.svg @@ -0,0 +1,503 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/XYPad.svg b/res/XYPad.svg index 688915b..d93a117 100644 --- a/res/XYPad.svg +++ b/res/XYPad.svg @@ -25,9 +25,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="5.6" - inkscape:cx="-7.955995" - inkscape:cy="363.56121" + inkscape:zoom="1.4" + inkscape:cx="182.20952" + inkscape:cy="185.6391" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" @@ -36,12 +36,14 @@ fit-margin-right="0" fit-margin-bottom="0" units="px" - inkscape:window-width="1593" - inkscape:window-height="1030" - inkscape:window-x="0" + inkscape:window-width="1021" + inkscape:window-height="757" + inkscape:window-x="843" inkscape:window-y="0" inkscape:window-maximized="0" - inkscape:snap-global="false"> + inkscape:snap-global="false" + inkscape:measure-start="0,0" + inkscape:measure-end="0,0"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/BouncyBall.cpp b/src/BouncyBall.cpp index 7bd16a8..4655c7d 100644 --- a/src/BouncyBall.cpp +++ b/src/BouncyBall.cpp @@ -4,34 +4,54 @@ struct BouncyBall : Module { enum ParamIds { - X_POS_PARAM, - Y_POS_PARAM, GATE_PARAM, + SCALE_X_PARAM, + SCALE_Y_PARAM, OFFSET_X_VOLTS_PARAM, OFFSET_Y_VOLTS_PARAM, + VELOCITY_X_PARAM, + VELOCITY_Y_PARAM, + SPEED_MULT_PARAM, + DECAY_PARAM, + GRAVITY_PARAM, NUM_PARAMS }; enum InputIds { + RESET_INPUT, + BUMP_INPUT, NUM_INPUTS }; enum OutputIds { X_OUTPUT, Y_OUTPUT, - GATE_OUTPUT, + NORTH_GATE_OUTPUT, + EAST_GATE_OUTPUT, + SOUTH_GATE_OUTPUT, + WEST_GATE_OUTPUT, NUM_OUTPUTS }; float minX = 0, minY = 0, maxX = 0, maxY = 0; float displayWidth = 0, displayHeight = 0; - float totalBallSize = 12; + float ballRadius = 10; + float ballStrokeWidth = 2; float minVolt = -5, maxVolt = 5; - PulseGenerator gatePulse; + float velScale = 0.01; + + bool lastTickWasEdgeHit = false; + long consecutiveEdgeHits = 0; + + Vec velocity; + Vec ballPos; + Vec ballVel; + + PulseGenerator northGatePulse, eastGatePulse, southGatePulse, westGatePulse; + SchmittTrigger resetTrigger; + SchmittTrigger bumpTrigger; BouncyBall() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {} void step(); - void reset(){ - defaultPos(); - } + void reset(){} json_t *toJson() { json_t *rootJ = json_object(); @@ -41,76 +61,95 @@ struct BouncyBall : Module { void fromJson(json_t *rootJ) { } - void defaultPos() { - params[BouncyBall::X_POS_PARAM].value = displayWidth / 2.0; - params[BouncyBall::Y_POS_PARAM].value = displayHeight / 2.0; - } - void updateMinMax(){ - minX = totalBallSize; - minY = totalBallSize; - maxX = displayWidth - totalBallSize; - maxY = displayHeight - totalBallSize; + float distToMid = ballRadius + ballStrokeWidth; + minX = distToMid; + minY = distToMid; + maxX = displayWidth - distToMid; + maxY = displayHeight - distToMid; + } + void resetBall(){ + ballPos.x = displayWidth * 0.5; + ballPos.y = displayHeight * 0.5; + consecutiveEdgeHits = 0; + lastTickWasEdgeHit = false; } }; void BouncyBall::step() { - outputs[X_OUTPUT].value = rescalef(params[X_POS_PARAM].value, minX, maxX, minVolt, maxVolt) + params[OFFSET_X_VOLTS_PARAM].value; - outputs[Y_OUTPUT].value = rescalef(params[Y_POS_PARAM].value, minY, maxY, maxVolt, minVolt) + params[OFFSET_Y_VOLTS_PARAM].value;//y is inverted because gui coords - - bool pulse = gatePulse.process(1.0 / engineGetSampleRate()); - outputs[GATE_OUTPUT].value = pulse ? 10.0 : 0.0; -} - -struct BouncyBallDisplay : Widget { - BouncyBall *module; - Vec velocity; - Vec gravity; - Vec ballPos; - float slowRate; - int totalBallSize = 15; + velocity = Vec(params[VELOCITY_X_PARAM].value, params[VELOCITY_Y_PARAM].value); - BouncyBallDisplay(){ init(); } + if (resetTrigger.process(inputs[RESET_INPUT].value)) { + resetBall(); + ballVel = Vec(velocity.mult(velScale)); + } - void onMouseDown(EventMouseDown &e) override { - init(); - module->params[BouncyBall::X_POS_PARAM].value = e.pos.x; - module->params[BouncyBall::Y_POS_PARAM].value = e.pos.y; + if (bumpTrigger.process(inputs[BUMP_INPUT].value)) { + ballVel = ballVel.plus(velocity.mult(velScale)); } - void init(){ - velocity = Vec(randomf()*4-2, randomf()*4-2); - gravity = Vec(0, randomf()*1); - slowRate = 0.75; + if(consecutiveEdgeHits < 5){//don't want to get stuck triggering on edges + + bool edgeHit = false; + if(ballPos.x >= maxX){ + ballVel.x *= -params[DECAY_PARAM].value;//-1 reverses ball with no speed change + eastGatePulse.trigger(1e-3); + edgeHit = true; + } + + if(ballPos.x <= minX){ + ballVel.x *= -params[DECAY_PARAM].value;//-1 reverses ball with no speed change + westGatePulse.trigger(1e-3); + edgeHit = true; + } + + if(ballPos.y >= maxY){ + ballVel.y *= -params[DECAY_PARAM].value;//-1 reverses ball with no speed change + southGatePulse.trigger(1e-3); + edgeHit = true; + } + + if(ballPos.y <= minY){ + ballVel.y *= -params[DECAY_PARAM].value;//-1 reverses ball with no speed change + northGatePulse.trigger(1e-3); + edgeHit = true; + } + + if(edgeHit){ + consecutiveEdgeHits++; + lastTickWasEdgeHit = true; + } else { + consecutiveEdgeHits = 0; + lastTickWasEdgeHit = false; + } } - void draw(NVGcontext *vg) override { - ballPos.x = module->params[BouncyBall::X_POS_PARAM].value; - ballPos.y = module->params[BouncyBall::Y_POS_PARAM].value; - ballPos = ballPos.plus(velocity); - velocity = velocity.plus(gravity); - - if(ballPos.x+totalBallSize > box.size.x || ballPos.x-totalBallSize < 0){ - velocity.x *= -1; - } - - if(ballPos.y+totalBallSize+2 > box.size.y){ - // if(slowRate > 0.1){ - velocity.y *= -(slowRate); - velocity.x *= slowRate; - ballPos.y = box.size.y-totalBallSize; - if(velocity.x < -0.02 || velocity.x > 0.02){ - printf("%f, %f\n", velocity.x, velocity.y); - module->gatePulse.trigger(1e-3); - } - // slowRate *= 0.5; - // } else { - // velocity.x = 0; - // velocity.y = 0; - // } - } + bool northPulse = northGatePulse.process(1.0 / engineGetSampleRate()); + bool eastPulse = eastGatePulse.process(1.0 / engineGetSampleRate()); + bool southPulse = southGatePulse.process(1.0 / engineGetSampleRate()); + bool westPulse = westGatePulse.process(1.0 / engineGetSampleRate()); + outputs[NORTH_GATE_OUTPUT].value = northPulse ? 10.0 : 0.0; + outputs[EAST_GATE_OUTPUT].value = eastPulse ? 10.0 : 0.0; + outputs[SOUTH_GATE_OUTPUT].value = southPulse ? 10.0 : 0.0; + outputs[WEST_GATE_OUTPUT].value = westPulse ? 10.0 : 0.0; + + outputs[X_OUTPUT].value = (rescalef(ballPos.x, minX, maxX, minVolt, maxVolt) + params[OFFSET_X_VOLTS_PARAM].value) * params[SCALE_X_PARAM].value; + outputs[Y_OUTPUT].value = (rescalef(ballPos.y, minY, maxY, maxVolt, minVolt) + params[OFFSET_Y_VOLTS_PARAM].value) * params[SCALE_Y_PARAM].value;//y is inverted because gui coords + + Vec newPos = ballPos.plus(ballVel.mult(params[SPEED_MULT_PARAM].value)); + ballPos.x = clampf(newPos.x, minX, maxX); + ballPos.y = clampf(newPos.y, minY, maxY); + +//TODO ADD GRAVITY for a more realistic bouncy ball + // ballVel = ballVel.plus(gravity); +} + +struct BouncyBallDisplay : Widget { + BouncyBall *module; + BouncyBallDisplay(){} + void draw(NVGcontext *vg) override { //background nvgFillColor(vg, nvgRGB(20, 30, 33)); nvgBeginPath(vg); @@ -122,12 +161,9 @@ struct BouncyBallDisplay : Widget { nvgStrokeColor(vg, nvgRGB(25, 150, 252)); nvgStrokeWidth(vg, 2); nvgBeginPath(vg); - nvgCircle(vg, ballPos.x, ballPos.y, totalBallSize - 2/*stroke*/); + nvgCircle(vg, module->ballPos.x, module->ballPos.y, module->ballRadius); nvgFill(vg); nvgStroke(vg); - - module->params[BouncyBall::X_POS_PARAM].value = ballPos.x; - module->params[BouncyBall::Y_POS_PARAM].value = ballPos.y; } }; @@ -136,60 +172,48 @@ BouncyBallWidget::BouncyBallWidget() { setModule(module); box.size = Vec(RACK_GRID_WIDTH*24, RACK_GRID_HEIGHT); - { - LightPanel *panel = new LightPanel(); - panel->box.size = box.size; - addChild(panel); - } + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/BouncyBall.svg"))); + addChild(panel); + + BouncyBallDisplay *display = new BouncyBallDisplay(); + display->module = module; + display->box.pos = Vec(2, 40); + display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 80); + addChild(display); + module->displayWidth = display->box.size.x; + module->displayHeight = display->box.size.y; + module->updateMinMax(); + module->resetBall(); + + addChild(createScrew(Vec(40, 20))); + addChild(createScrew(Vec(55, 20))); + + //top row + addParam(createParam(Vec(140, 20), module, BouncyBall::SCALE_X_PARAM, 0.01, 1.0, 0.5)); + addParam(createParam(Vec(200, 20), module, BouncyBall::SCALE_Y_PARAM, 0.01, 1.0, 0.5)); + addParam(createParam(Vec(260, 20), module, BouncyBall::OFFSET_X_VOLTS_PARAM, -5.0, 5.0, 5.0)); + addParam(createParam(Vec(320, 20), module, BouncyBall::OFFSET_Y_VOLTS_PARAM, -5.0, 5.0, 5.0)); + + //bottom row + addInput(createInput(Vec(20, 360), module, BouncyBall::RESET_INPUT)); + addInput(createInput(Vec(60, 360), module, BouncyBall::BUMP_INPUT)); - { - BouncyBallDisplay *display = new BouncyBallDisplay(); - display->module = module; - display->box.pos = Vec(2, 2); - display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 40); - addChild(display); - - module->displayWidth = display->box.size.x; - module->displayHeight = display->box.size.y; - module->updateMinMax(); - module->defaultPos(); - } + addParam(createParam(Vec(100, 360), module, BouncyBall::VELOCITY_X_PARAM, -1.0, 1.0, 0.0)); + addParam(createParam(Vec(130, 360), module, BouncyBall::VELOCITY_Y_PARAM, -1.0, 1.0, 0.0)); + addParam(createParam(Vec(165, 360), module, BouncyBall::SPEED_MULT_PARAM, 1.0, 20.0, 1.0)); - rack::Label* const titleLabel = new rack::Label; - titleLabel->box.pos = Vec(3, 350); - titleLabel->text = "Bouncy Ball"; - addChild(titleLabel); - - //////////////////////////////////////////////////////////// - rack::Label* const xOffsetLabel = new rack::Label; - xOffsetLabel->box.pos = Vec(120-20, 340); - xOffsetLabel->text = "X OFST"; - addChild(xOffsetLabel); - - rack::Label* const yOffsetLabel = new rack::Label; - yOffsetLabel->box.pos = Vec(180-20, 340); - yOffsetLabel->text = "Y OFST"; - addChild(yOffsetLabel); - - rack::Label* const xLabel = new rack::Label; - xLabel->box.pos = Vec(240-4, 340); - xLabel->text = "X"; - addChild(xLabel); - - rack::Label* const yLabel = new rack::Label; - yLabel->box.pos = Vec(260-4, 340); - yLabel->text = "Y"; - addChild(yLabel); - - rack::Label* const gLabel = new rack::Label; - gLabel->box.pos = Vec(340-5, 340); - gLabel->text = "G"; - addChild(gLabel); - - addParam(createParam(Vec(120, 360), module, BouncyBall::OFFSET_X_VOLTS_PARAM, -5.0, 5.0, 0.0)); - addParam(createParam(Vec(180, 360), module, BouncyBall::OFFSET_Y_VOLTS_PARAM, -5.0, 5.0, 0.0)); - addOutput(createOutput(Vec(240, 360), module, BouncyBall::X_OUTPUT)); - addOutput(createOutput(Vec(260, 360), module, BouncyBall::Y_OUTPUT)); - addOutput(createOutput(Vec(340, 360), module, BouncyBall::GATE_OUTPUT)); +//TODO ADD Gravity knob back in and add labels in SVG + // addParam(createParam(Vec(195, 360), module, BouncyBall::GRAVITY_PARAM, -1.0, 1.0, 0.0)); + + addParam(createParam(Vec(195, 360), module, BouncyBall::DECAY_PARAM, 1.0, 0.0, 1.0)); + + addOutput(createOutput(Vec(225, 360), module, BouncyBall::X_OUTPUT)); + addOutput(createOutput(Vec(250, 360), module, BouncyBall::Y_OUTPUT)); + addOutput(createOutput(Vec(280, 360), module, BouncyBall::NORTH_GATE_OUTPUT)); + addOutput(createOutput(Vec(300, 360), module, BouncyBall::EAST_GATE_OUTPUT)); + addOutput(createOutput(Vec(320, 360), module, BouncyBall::SOUTH_GATE_OUTPUT)); + addOutput(createOutput(Vec(340, 360), module, BouncyBall::WEST_GATE_OUTPUT)); } diff --git a/src/JWModules.cpp b/src/JWModules.cpp index 2da65ee..49a34df 100644 --- a/src/JWModules.cpp +++ b/src/JWModules.cpp @@ -10,12 +10,13 @@ void init(rack::Plugin *p) { p->version = TOSTRING(VERSION); #endif std::string me = "JW-Modules"; - p->addModel(createModel(me, "FullScope", "FullScope", VISUAL_TAG)); - p->addModel(createModel(me, "GridSeq", "GridSeq", SEQUENCER_TAG)); - p->addModel(createModel(me, "Quantizer", "Quantizer", QUANTIZER_TAG)); - p->addModel(createModel(me, "MinMax", "MinMax", UTILITY_TAG)); - p->addModel(createModel(me, "SimpleClock", "SimpleClock", CLOCK_TAG, RANDOM_TAG)); - p->addModel(createModel("JW-Modules", "WavHead", "WavHead", VISUAL_TAG)); - p->addModel(createModel(me, "XYPad", "XYPad", LFO_TAG, ENVELOPE_GENERATOR_TAG, RANDOM_TAG, OSCILLATOR_TAG, SAMPLE_AND_HOLD_TAG)); - // p->addModel(createModel("JW-Modules", "JW-Modules", "BouncyBall", "BouncyBall")); + // DON'T CHANGE SLUG LABEL + p->addModel(createModel(me, "FullScope", "FullScope", VISUAL_TAG)); + p->addModel(createModel(me, "GridSeq", "GridSeq", SEQUENCER_TAG)); + p->addModel(createModel(me, "Quantizer", "Quantizer", QUANTIZER_TAG)); + p->addModel(createModel(me, "MinMax", "MinMax", UTILITY_TAG)); + p->addModel(createModel(me, "SimpleClock", "SimpleClock", CLOCK_TAG, RANDOM_TAG)); + p->addModel(createModel(me, "WavHead", "WavHead", VISUAL_TAG)); + p->addModel(createModel(me, "XYPad", "XYPad", LFO_TAG, ENVELOPE_GENERATOR_TAG, RANDOM_TAG, OSCILLATOR_TAG, SAMPLE_AND_HOLD_TAG)); + // p->addModel(createModel(me, "BouncyBall", "BouncyBall", SEQUENCER_TAG, VISUAL_TAG)); } diff --git a/src/JWModules.hpp b/src/JWModules.hpp index a43bd83..1fe35c5 100644 --- a/src/JWModules.hpp +++ b/src/JWModules.hpp @@ -260,3 +260,10 @@ struct ScaleKnob : SmallWhiteKnob { return quantizeUtils->scaleName(int(value)); } }; + +struct BPMKnob : SmallWhiteKnob { + BPMKnob(){} + std::string formatCurrentValue() { + return std::to_string(static_cast(powf(2.0, value)*60.0)) + " BPM"; + } +}; diff --git a/src/SimpleClock.cpp b/src/SimpleClock.cpp index e8f856c..626813d 100644 --- a/src/SimpleClock.cpp +++ b/src/SimpleClock.cpp @@ -86,7 +86,6 @@ void SimpleClock::step() { if (phase >= 1.0) { phase -= 1.0; nextStep = true; - // lights[CLOCK_LIGHT].value = 1.0; } } if (nextStep) { @@ -132,9 +131,16 @@ SimpleClockWidget::SimpleClockWidget() { addParam(createParam(Vec(23, 40), module, SimpleClock::RUN_PARAM, 0.0, 1.0, 0.0)); addChild(createLight>(Vec(23+3.75, 40+3.75), module, SimpleClock::RUNNING_LIGHT)); - - addParam(createParam(Vec(17, 60), module, SimpleClock::CLOCK_PARAM, -2.0, 6.0, 2.0)); - addOutput(createOutput(Vec(18, 90), module, SimpleClock::CLOCK_OUTPUT)); + + BPMKnob *clockKnob = dynamic_cast(createParam(Vec(17, 60), module, SimpleClock::CLOCK_PARAM, -2.0, 6.0, 1.0)); + CenteredLabel* const bpmLabel = new CenteredLabel; + bpmLabel->box.pos = Vec(15, 50); + bpmLabel->text = "0"; + clockKnob->connectLabel(bpmLabel); + addChild(bpmLabel); + addParam(clockKnob); + + addOutput(createOutput(Vec(18, 105), module, SimpleClock::CLOCK_OUTPUT)); CenteredLabel* const resetLabel = new CenteredLabel; resetLabel->box.pos = Vec(15, 75); diff --git a/src/XYPad.cpp b/src/XYPad.cpp index 9ea306a..91e9569 100644 --- a/src/XYPad.cpp +++ b/src/XYPad.cpp @@ -311,7 +311,6 @@ struct XYPad : Module { minY = distToMid; maxX = displayWidth - distToMid; maxY = displayHeight - distToMid; - } bool isStatePlaying() { @@ -598,121 +597,39 @@ XYPadWidget::XYPadWidget() { setModule(module); box.size = Vec(RACK_GRID_WIDTH*24, RACK_GRID_HEIGHT); - { - SVGPanel *panel = new SVGPanel(); - panel->box.size = box.size; - panel->setBackground(SVG::load(assetPlugin(plugin, "res/XYPad.svg"))); - addChild(panel); - } - { - XYPadDisplay *display = new XYPadDisplay(); - display->module = module; - display->box.pos = Vec(2, 40); - display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 80); - addChild(display); + SVGPanel *panel = new SVGPanel(); + panel->box.size = box.size; + panel->setBackground(SVG::load(assetPlugin(plugin, "res/XYPad.svg"))); + addChild(panel); - module->displayWidth = display->box.size.x; - module->displayHeight = display->box.size.y; - module->updateMinMax(); - module->defaultPos(); - } + XYPadDisplay *display = new XYPadDisplay(); + display->module = module; + display->box.pos = Vec(2, 40); + display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 80); + addChild(display); + + module->displayWidth = display->box.size.x; + module->displayHeight = display->box.size.y; + module->updateMinMax(); + module->defaultPos(); - //////////////////////////////////////////////////////////// - CenteredLabel* const titleLabel = new CenteredLabel(16); - titleLabel->box.pos = Vec(27, 8); - titleLabel->text = "XY Pad"; - addChild(titleLabel); addChild(createScrew(Vec(40, 20))); addChild(createScrew(Vec(55, 20))); - - rack::Label* const rndLabel = new rack::Label; - rndLabel->box.pos = Vec(85, 2); - rndLabel->text = "Rnd"; - addChild(rndLabel); - - rack::Label* const xScaleLabel = new rack::Label; - xScaleLabel->box.pos = Vec(140-20, 2); - xScaleLabel->text = "X Scale"; - addChild(xScaleLabel); - - rack::Label* const yScaleLabel = new rack::Label; - yScaleLabel->box.pos = Vec(200-20, 2); - yScaleLabel->text = "Y Scale"; - addChild(yScaleLabel); - - rack::Label* const xOffsetLabel = new rack::Label; - xOffsetLabel->box.pos = Vec(260-20, 2); - xOffsetLabel->text = "X Offset"; - addChild(xOffsetLabel); - - rack::Label* const yOffsetLabel = new rack::Label; - yOffsetLabel->box.pos = Vec(320-20, 2); - yOffsetLabel->text = "Y Offset"; - addChild(yOffsetLabel); - addParam(createParam(Vec(90, 20), module, XYPad::RND_SHAPES_PARAM, 0.0, 1.0, 0.0)); addParam(createParam(Vec(105, 20), module, XYPad::RND_VARIATION_PARAM, 0.0, 1.0, 0.0)); - addParam(createParam(Vec(140, 20), module, XYPad::SCALE_X_PARAM, 0.01, 1.0, 0.5)); addParam(createParam(Vec(200, 20), module, XYPad::SCALE_Y_PARAM, 0.01, 1.0, 0.5)); addParam(createParam(Vec(260, 20), module, XYPad::OFFSET_X_VOLTS_PARAM, -5.0, 5.0, 5.0)); addParam(createParam(Vec(320, 20), module, XYPad::OFFSET_Y_VOLTS_PARAM, -5.0, 5.0, 5.0)); //////////////////////////////////////////////////////////// - rack::Label* const trigLabel = new rack::Label; - trigLabel->box.pos = Vec(5, 340); - trigLabel->text = "Gate In"; - addChild(trigLabel); - - rack::Label* const autoLabel = new rack::Label; - autoLabel->box.pos = Vec(78-20, 340); - autoLabel->text = "Auto"; - addChild(autoLabel); - - rack::Label* const speedLabel = new rack::Label; - speedLabel->box.pos = Vec(122-20, 340); - speedLabel->text = "Speed"; - addChild(speedLabel); - - rack::Label* const speedMultLabel = new rack::Label; - speedMultLabel->box.pos = Vec(145, 340); - speedMultLabel->text = "Mult"; - addChild(speedMultLabel); - - rack::Label* const xLabel = new rack::Label; - xLabel->box.pos = Vec(195-4, 340); - xLabel->text = "X"; - addChild(xLabel); - - rack::Label* const yLabel = new rack::Label; - yLabel->box.pos = Vec(220-4, 340); - yLabel->text = "Y"; - addChild(yLabel); - - rack::Label* const xInvLabel = new rack::Label; - xInvLabel->box.pos = Vec(255-7, 340); - xInvLabel->text = "-X"; - addChild(xInvLabel); - - rack::Label* const yInvLabel = new rack::Label; - yInvLabel->box.pos = Vec(280-7, 340); - yInvLabel->text = "-Y"; - addChild(yInvLabel); - - rack::Label* const gLabel = new rack::Label; - gLabel->box.pos = Vec(300-5, 340); - gLabel->text = "Gate Out"; - addChild(gLabel); addInput(createInput(Vec(25, 360), module, XYPad::PLAY_GATE_INPUT)); - addParam(createParam(Vec(71, 360), module, XYPad::AUTO_PLAY_PARAM, 0.0, 1.0, 0.0)); addChild(createLight>(Vec(71+3.75, 360+3.75), module, XYPad::AUTO_LIGHT)); - addInput(createInput(Vec(110, 360), module, XYPad::PLAY_SPEED_INPUT)); addParam(createParam(Vec(130, 360), module, XYPad::PLAY_SPEED_PARAM, 0.0, 10.0, 5.0)); addParam(createParam(Vec(157, 360), module, XYPad::SPEED_MULT_PARAM, 1.0, 100.0, 1.0)); - addOutput(createOutput(Vec(195, 360), module, XYPad::X_OUTPUT)); addOutput(createOutput(Vec(220, 360), module, XYPad::Y_OUTPUT)); addOutput(createOutput(Vec(255, 360), module, XYPad::X_INV_OUTPUT));