|
-
- #include "Southpole.hpp"
-
- #include "dsp/digital.hpp"
-
- namespace rack_plugin_Southpole {
-
- struct Fuse : Module {
- enum ParamIds {
- SWITCH1_PARAM,
- SWITCH2_PARAM,
- SWITCH3_PARAM,
- SWITCH4_PARAM,
- NUM_PARAMS
- };
-
- enum InputIds {
- ARM1_INPUT,
- ARM2_INPUT,
- ARM3_INPUT,
- ARM4_INPUT,
- CLK_INPUT,
- RESET_INPUT,
- NUM_INPUTS
- };
-
- enum OutputIds {
- OUT1_OUTPUT,
- OUT2_OUTPUT,
- OUT3_OUTPUT,
- OUT4_OUTPUT,
- NUM_OUTPUTS
- };
-
- enum LightIds {
- ARM1_LIGHT,
- ARM2_LIGHT,
- ARM3_LIGHT,
- ARM4_LIGHT,
- NUM_LIGHTS
- };
-
- bool gateMode;
-
- Fuse() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
-
- params.resize(NUM_PARAMS);
- inputs.resize(NUM_INPUTS);
- outputs.resize(NUM_OUTPUTS);
- lights.resize(NUM_LIGHTS);
- }
-
- void step() override;
-
- SchmittTrigger clockTrigger;
- SchmittTrigger resetTrigger;
- SchmittTrigger armTrigger[4];
- PulseGenerator pulse[4];
-
- bool armed[4];
- bool gateOn[4];
-
- const unsigned maxsteps = 16;
- unsigned curstep = 0;
-
-
- json_t *toJson() override {
- json_t *rootJ = json_object();
- json_object_set_new(rootJ, "gateMode", json_boolean( gateMode ));
- return rootJ;
- }
-
- void fromJson(json_t *rootJ) override {
- json_t *gateModeJ = json_object_get(rootJ, "gateMode");
- if (gateModeJ) {
- gateMode = json_boolean_value(gateModeJ);
- }
- }
- };
-
- void Fuse::step() {
-
- bool nextStep = false;
-
- if (inputs[RESET_INPUT].active) {
- if (resetTrigger.process(inputs[RESET_INPUT].value)) {
- curstep = maxsteps;
- for (unsigned int i=0; i<4; i++) {
- armTrigger[i].reset();
- armed[i] = false;
- gateOn[i] = false;
- }
- }
- }
-
- if (inputs[CLK_INPUT].active) {
- if (clockTrigger.process(inputs[CLK_INPUT].value)) {
- nextStep = true;
- }
- }
-
- if ( nextStep ) {
- curstep++;
- if ( curstep >= maxsteps ) curstep = 0;
-
- if ( curstep % 4 == 0 ) {
- unsigned int i = curstep/4;
- gateOn[(i-1)%4] = false;
-
- if ( armed[i] ) {
- pulse[i].trigger(1e-3);
- if ( gateMode ) gateOn[i] = true;
- armed[i] = false;
- }
- }
- //printf("%d %d\n",curstep,gateOn[curstep/4]);
- }
-
- for (unsigned int i=0; i<4; i++) {
-
- if ( params[SWITCH1_PARAM + i].value > 0. ) armed[i] = true;
- if ( armTrigger[i].process(inputs[ARM1_INPUT + i].normalize(0.))) armed[i] = true;
-
- lights[ARM1_LIGHT + i].setBrightness( armed[i] ? 1.0 : 0.0 );
-
- bool p = pulse[i].process(1.0 / engineGetSampleRate());
-
- if (gateOn[i]) p = true;
-
- outputs[OUT1_OUTPUT + i].value = p ? 10.0 : 0.0;
-
- }
- };
-
- struct FuseDisplay : TransparentWidget {
-
- Fuse *module;
-
- FuseDisplay() {}
-
- void draw(NVGcontext *vg) override {
-
- // Background
- NVGcolor backgroundColor = nvgRGB(0x30, 0x00, 0x10);
- NVGcolor borderColor = nvgRGB(0xd0, 0xd0, 0xd0);
- nvgBeginPath(vg);
- nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 5.0);
- nvgFillColor(vg, backgroundColor);
- nvgFill(vg);
- nvgStrokeWidth(vg, 1.5);
- nvgStrokeColor(vg, borderColor);
- nvgStroke(vg);
-
- // Lights
- nvgStrokeColor(vg, nvgRGBA(0x7f, 0x00, 0x00, 0xff));
- nvgFillColor(vg, nvgRGBA(0xff, 0x00, 0x00, 0xff));
- for ( unsigned y_ = 0; y_ < 16; y_++ ) {
- unsigned y = 15 - y_;
- nvgBeginPath(vg);
- nvgStrokeWidth(vg, 1.);
- nvgRect(vg, 3., y*box.size.y/18.+7.*floor(y/4.)+9., box.size.x-6., box.size.y/18.-6.);
- if (y_ <= module->curstep) nvgFill(vg);
- nvgStroke(vg);
- }
-
- }
- };
-
- struct FuseWidget : ModuleWidget {
- Menu *createContextMenu() override;
-
- FuseWidget(Fuse *module) : ModuleWidget(module) {
-
- box.size = Vec(4 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
- {
- SVGPanel *panel = new SVGPanel();
- panel->box.size = box.size;
- panel->setBackground(SVG::load(assetPlugin(plugin, "res/Fuse.svg")));
- addChild(panel);
- }
-
- {
- FuseDisplay *display = new FuseDisplay();
- display->module = module;
- display->box.pos = Vec( 32, 25.);
- display->box.size = Vec( 24., box.size.y-85. );
- addChild(display);
- }
-
- float y1 = 76;
- float yh = 73;
- float x1 = 5;
- float x2 = 35;
-
- for(int i = 0; i < 4; i++)
- {
- addParam(ParamWidget::create<LEDButton>(Vec(x1+1, y1 + i*yh-22), module, Fuse::SWITCH1_PARAM + 3 - i, 0.0, 1.0, 0.0));
- addChild(ModuleLightWidget::create<MediumLight<YellowLight>>(Vec(x1+5, y1+ i*yh-18), module, Fuse::ARM1_LIGHT + 3 - i));
- addInput(Port::create<sp_Port>(Vec(x1, y1 + i*yh-45), Port::INPUT, module, Fuse::ARM1_INPUT + 3 - i));
- addOutput(Port::create<sp_Port>(Vec(x1, y1 + i*yh), Port::OUTPUT, module, Fuse::OUT1_OUTPUT + 3 - i));
- }
-
- addInput(Port::create<sp_Port>(Vec(x1, 330), Port::INPUT, module, Fuse::CLK_INPUT));
- addInput(Port::create<sp_Port>(Vec(x2, 330), Port::INPUT, module, Fuse::RESET_INPUT));
- }
- };
-
- struct FuseGateModeItem : MenuItem {
- Fuse *fuse;
- bool gateMode;
- void onAction(EventAction &e) override {
- fuse->gateMode = gateMode;
- }
- void step() override {
- rightText = (fuse->gateMode == gateMode) ? "✔" : "";
- }
- };
-
- Menu *FuseWidget::createContextMenu() {
- Menu *menu = ModuleWidget::createContextMenu();
-
- MenuLabel *spacerLabel = new MenuLabel();
- menu->addChild(spacerLabel);
-
- Fuse *fuse = dynamic_cast<Fuse*>(module);
- assert(fuse);
-
- MenuLabel *modeLabel = new MenuLabel();
- modeLabel->text = "Gate Mode";
- menu->addChild(modeLabel);
-
- FuseGateModeItem *triggerItem = new FuseGateModeItem();
- triggerItem->text = "Trigger";
- triggerItem->fuse = fuse;
- triggerItem->gateMode = false;
- menu->addChild(triggerItem);
-
- FuseGateModeItem *gateItem = new FuseGateModeItem();
- gateItem->text = "Gate";
- gateItem->fuse = fuse;
- gateItem->gateMode = true;
- menu->addChild(gateItem);
-
- return menu;
- }
-
- } // namespace rack_plugin_Southpole
-
- using namespace rack_plugin_Southpole;
-
- RACK_PLUGIN_MODEL_INIT(Southpole, Fuse) {
- Model *modelFuse = Model::create<Fuse,FuseWidget>( "Southpole", "Fuse", "Fuse - next pattern", SEQUENCER_TAG);
- return modelFuse;
- }
|