computerscare-vcv-modules

computerscare modules for VCV Rack
Log | Files | Refs

commit 2a684640af4eae5f566be750238613a46542debe
parent 26efd784ab60d77e69088f6f0f98f44cc22931f8
Author: Adam M <aemalone@gmail.com>
Date:   Wed,  3 Jul 2019 20:50:52 -0500

Laundry Soup finally does not crash

Diffstat:
MMakefile | 1+
Mplugin.json | 6++++++
Msrc/Computerscare.cpp | 2+-
Msrc/Computerscare.hpp | 8++++----
Msrc/ComputerscareLaundrySoup.cpp | 508++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/ComputerscarePatchSequencer.cpp | 2+-
6 files changed, 321 insertions(+), 206 deletions(-)

diff --git a/Makefile b/Makefile @@ -18,6 +18,7 @@ SOURCES += $(wildcard src/ComputerscareSvgPort.cpp) SOURCES += $(wildcard src/ComputerscareIso.cpp) SOURCES += $(wildcard src/ComputerscareKnolyPobs.cpp) SOURCES += $(wildcard src/ComputerscarePatchSequencer.cpp) +SOURCES += $(wildcard src/ComputerscareLaundrySoup.cpp) SOURCES += $(wildcard src/ComputerscareDebug.cpp) SOURCES += $(wildcard src/ComputerscareOhPeas.cpp) diff --git a/plugin.json b/plugin.json @@ -29,6 +29,12 @@ "name":"Father and Son Patch Sequencer", "description":"Patch Sequencer - 10 in, 10 out patch matrix with 16 scenes", "tags":["Poly","Utility"] + }, + + {"slug":"computerscare-laundry-soup", + "name":"Laundry Soup", + "description":"Rhythm sequencer, pulse generator, text-based", + "tags":["Sequencer"] } ] } \ No newline at end of file diff --git a/src/Computerscare.cpp b/src/Computerscare.cpp @@ -9,7 +9,7 @@ void init(Plugin *p) { p->addModel(modelComputerscareDebug); p->addModel(modelComputerscarePatchSequencer); - //p->addModel(modelComputerscareLaundrySoup); + p->addModel(modelComputerscareLaundrySoup); //p->addModel(modelComputerscareILoveCookies); p->addModel(modelComputerscareOhPeas); //p->addModel(modelComputerscareIso); diff --git a/src/Computerscare.hpp b/src/Computerscare.hpp @@ -27,7 +27,7 @@ extern Model *modelComputerscareDebug; extern Model *modelComputerscarePatchSequencer; -//extern Model *modelComputerscareLaundrySoup; +extern Model *modelComputerscareLaundrySoup; //extern Model *modelComputerscareILoveCookies; extern Model *modelComputerscareOhPeas; //extern Model *modelComputerscareIso; @@ -100,7 +100,7 @@ struct ComputerscareDebugFour : app::SvgSwitch { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/debug-clock-selector-4way-template.svg"))); } }; -struct ComputerscareResetButton : SvgSwitch { +struct ComputerscareResetButton : app::SvgSwitch { ComputerscareResetButton() { momentary = true; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-rst-text.svg"))); @@ -109,14 +109,14 @@ struct ComputerscareResetButton : SvgSwitch { } }; -struct ComputerscareClockButton : SvgSwitch { +struct ComputerscareClockButton : app::SvgSwitch { ComputerscareClockButton() { momentary = true; addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-clk-text.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-clk-text-red.svg"))); } }; -struct ComputerscareInvisibleButton : SvgSwitch { +struct ComputerscareInvisibleButton : app::SvgSwitch { ComputerscareInvisibleButton() { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-invisible-button.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/computerscare-invisible-button-frame2.svg"))); diff --git a/src/ComputerscareLaundrySoup.cpp b/src/ComputerscareLaundrySoup.cpp @@ -9,204 +9,167 @@ #include <iomanip> struct ComputerscareLaundrySoup; +struct LaundryTextField; +struct LaundryTF2; +struct LaundrySmallDisplay; + const int numFields = 6; -class MyTextField : public LedDisplayTextField { +/*class MyTextField : public LedDisplayTextField { public: int fontSize = 16; - int rowIndex=0; + int rowIndex = 0; bool inError = false; MyTextField() : LedDisplayTextField() {} void setModule(ComputerscareLaundrySoup* _module) { module = _module; } - virtual void onTextChange() override; + //virtual void onTextChange() override; int getTextPosition(Vec mousePos) override { bndSetFont(font->handle); int textPos = bndIconLabelTextPosition(gVg, textOffset.x, textOffset.y, - box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, - -1, fontSize, text.c_str(), mousePos.x, mousePos.y); + box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, + -1, fontSize, text.c_str(), mousePos.x, mousePos.y); bndSetFont(gGuiFont->handle); return textPos; } - void draw(const DrawArgs &args) override { - nvgScissor(args.vg, 0, 0, box.size.x, box.size.y); +*/ - // Background - nvgFontSize(args.vg, fontSize); - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, 0, 0, box.size.x, box.size.y, 10.0); - - if(inError) { - nvgFillColor(args.vg, COLOR_COMPUTERSCARE_PINK); - } - else { - nvgFillColor(args.vg, nvgRGB(0x00, 0x00, 0x00)); - } - nvgFill(args.vg); - - // Text - if (font->handle >= 0) { - bndSetFont(font->handle); - - NVGcolor highlightColor = color; - highlightColor.a = 0.5; - int begin = min(cursor, selection); - int end = (this == gFocusedWidget) ? max(cursor, selection) : -1; - //bndTextField(args.vg,textOffset.x,textOffset.y+2, box.size.x, box.size.y, -1, 0, 0, const char *text, int cbegin, int cend); - bndIconLabelCaret(args.vg, textOffset.x, textOffset.y - 3, - box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, - -1, color, fontSize, text.c_str(), highlightColor, begin, end); - - bndSetFont(gGuiFont->handle); - } - - nvgResetScissor(args.vg); - }; +/*void MyTextField::onTextChange() { + std::string value = module->textFields[this->rowIndex]->text; + LaundrySoupSequence lss = LaundrySoupSequence(value); -private: - ComputerscareLaundrySoup* module; -}; + if(!lss.inError && matchParens(value)) { + module->textFields[this->rowIndex]->inError=false; + module->setNextAbsoluteSequence(this->rowIndex); + module->updateDisplayBlink(this->rowIndex); + } + else { + module->textFields[this->rowIndex]->inError=true; + } +}*/ struct ComputerscareLaundrySoup : Module { - enum ParamIds { - MANUAL_CLOCK_PARAM, - MANUAL_RESET_PARAM, - INDIVIDUAL_RESET_PARAM, - NUM_PARAMS = INDIVIDUAL_RESET_PARAM + numFields - }; - enum InputIds { + enum ParamIds { + MANUAL_CLOCK_PARAM, + MANUAL_RESET_PARAM, + INDIVIDUAL_RESET_PARAM, + NUM_PARAMS = INDIVIDUAL_RESET_PARAM + numFields + }; + enum InputIds { GLOBAL_CLOCK_INPUT, GLOBAL_RESET_INPUT, CLOCK_INPUT, RESET_INPUT = CLOCK_INPUT + numFields, - NUM_INPUTS = RESET_INPUT + numFields - }; - enum OutputIds { + NUM_INPUTS = RESET_INPUT + numFields + }; + enum OutputIds { TRG_OUTPUT, FIRST_STEP_OUTPUT = TRG_OUTPUT + numFields, - NUM_OUTPUTS = FIRST_STEP_OUTPUT + numFields - }; + NUM_OUTPUTS = FIRST_STEP_OUTPUT + numFields + }; enum LightIds { - SWITCH_LIGHTS, + SWITCH_LIGHTS, NUM_LIGHTS - }; + }; + + rack::dsp::SchmittTrigger globalClockTrigger; + rack::dsp::SchmittTrigger globalResetTriggerInput; - SchmittTrigger globalClockTrigger; - SchmittTrigger globalResetTriggerInput; + rack::dsp::SchmittTrigger globalManualClockTrigger; + rack::dsp::SchmittTrigger globalManualResetTrigger; - SchmittTrigger globalManualClockTrigger; - SchmittTrigger globalManualResetTrigger; + rack::dsp::SchmittTrigger clockTriggers[numFields]; + rack::dsp::SchmittTrigger resetTriggers[numFields]; - SchmittTrigger clockTriggers[numFields]; - SchmittTrigger resetTriggers[numFields]; + LaundryTF2* textFields[numFields]; + LaundrySmallDisplay* smallLetterDisplays[numFields]; - MyTextField* textFields[numFields]; - SmallLetterDisplay* smallLetterDisplays[numFields]; + std::string currentFormula[numFields]; - SchmittTrigger manualResetTriggers[numFields]; + rack::dsp::SchmittTrigger manualResetTriggers[numFields]; LaundrySoupSequence laundrySequences[numFields]; bool activeStep[numFields] = {false}; bool shouldChange[numFields] = {false}; - -ComputerscareLaundrySoup() { - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);} - void process(const ProcessArgs &args) override; - json_t *toJson() override - { - json_t *rootJ = json_object(); - - json_t *sequencesJ = json_array(); + ComputerscareLaundrySoup() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); for (int i = 0; i < numFields; i++) { - json_t *sequenceJ = json_string(textFields[i]->text.c_str()); - json_array_append_new(sequencesJ, sequenceJ); - } - json_object_set_new(rootJ, "sequences", sequencesJ); - - return rootJ; - } - - void fromJson(json_t *rootJ) override - { - json_t *sequencesJ = json_object_get(rootJ, "sequences"); - if (sequencesJ) { - for (int i = 0; i < numFields; i++) { + currentFormula[i] = ""; + setNextAbsoluteSequence(i); + checkIfShouldChange(i); + resetOneOfThem(i); - json_t *sequenceJ = json_array_get(sequencesJ, i); - if (sequenceJ) - textFields[i]->text = json_string_value(sequenceJ); - } } - onCreate(); } - + void process(const ProcessArgs &args) override; + + + void onRandomize() override { - randomizeAllFields(); + //randomizeAllFields(); } - void randomizeAllFields() { - std::string mainlookup ="111111111111111111122223333333344444444444444445556667778888888888888999"; - std::string string = ""; - std::string randchar = ""; - int length = 0; + /* void randomizeAllFields() { + std::string mainlookup = "111111111111111111122223333333344444444444444445556667778888888888888999"; + std::string string = ""; + std::string randchar = ""; + int length = 0; - for (int i = 0; i < numFields; i++) { - length = rand() % 12 + 1; - string = ""; - for(int j = 0; j < length; j++) { - randchar = mainlookup[rand() % mainlookup.size()]; - string = string + randchar; + for (int i = 0; i < numFields; i++) { + length = rand() % 12 + 1; + string = ""; + for (int j = 0; j < length; j++) { + randchar = mainlookup[rand() % mainlookup.size()]; + string = string + randchar; + } + textFields[i]->text = string; + setNextAbsoluteSequence(i); } - textFields[i]->text = string; - setNextAbsoluteSequence(i); - } - } + }*/ -void setNextAbsoluteSequence(int index) { - shouldChange[index] = true; -} -void setAbsoluteSequenceFromQueue(int index) { - LaundrySoupSequence lss = LaundrySoupSequence(textFields[index]->text); - laundrySequences[index] = lss; - if(!lss.inError) { - laundrySequences[index] = lss; - //laundrySequences[index].print(); - textFields[index]->inError=false; + void setNextAbsoluteSequence(int index) { + shouldChange[index] = true; } - else { - printf("ERROR\n"); - //lss.print(); - textFields[index]->inError=true; + void setAbsoluteSequenceFromQueue(int index) { + LaundrySoupSequence lss = LaundrySoupSequence(currentFormula[index]); + laundrySequences[index] = lss; + if (!lss.inError) { + laundrySequences[index] = lss; + laundrySequences[index].print(); + //textFields[index]->inError = false; + } + else { + printf("ERROR\n"); + lss.print(); + //textFields[index]->inError = true; + } } -} -void checkIfShouldChange(int index) { - if(shouldChange[index]) { - setAbsoluteSequenceFromQueue(index); - shouldChange[index] = false; - updateDisplayBlink(index); + void checkIfShouldChange(int index) { + if (shouldChange[index]) { + setAbsoluteSequenceFromQueue(index); + shouldChange[index] = false; + updateDisplayBlink(index); + } } -} -void updateDisplayBlink(int index) { - smallLetterDisplays[index]->blink = shouldChange[index]; -} -void onCreate () override + void updateDisplayBlink(int index) { + // smallLetterDisplays[index]->blink = shouldChange[index]; + } + void onCreate () { - for(int i = 0; i < numFields; i++) { - setNextAbsoluteSequence(i); - checkIfShouldChange(i); - resetOneOfThem(i); - } + printf("onCreate\n"); + } void onReset () override { + printf("onReset\n"); onCreate(); } @@ -220,25 +183,26 @@ void onCreate () override */ void incrementInternalStep(int i) { + laundrySequences[i].print(); laundrySequences[i].incrementAndCheck(); - if(laundrySequences[i].readHead == 0) { - this->setChangeImminent(i,false); + if (laundrySequences[i].readHead == 0) { + this->setChangeImminent(i, false); } - this->smallLetterDisplays[i]->value = this->getDisplayString(i); + //this->smallLetterDisplays[i]->value = this->getDisplayString(i); } std::string getDisplayString(int index) { std::string lhs = std::to_string(this->laundrySequences[index].readHead + 1); std::string rhs = std::to_string(this->laundrySequences[index].numSteps); - padTo(lhs, 3,' '); - padTo(rhs, 3,' '); - + padTo(lhs, 3, ' '); + padTo(rhs, 3, ' '); + std::string val = lhs + "\n" + rhs; return val; } - void setChangeImminent(int i,bool value) { - this->smallLetterDisplays[i]->doubleblink = value; + void setChangeImminent(int i, bool value) { + // this->smallLetterDisplays[i]->doubleblink = value; } void resetOneOfThem(int i) { this->laundrySequences[i].readHead = -1; @@ -263,21 +227,21 @@ void ComputerscareLaundrySoup::process(const ProcessArgs &args) { bool currentResetTriggered = false; bool currentManualResetClicked; - for(int i = 0; i < numFields; i++) { + for (int i = 0; i < numFields; i++) { currentResetActive = inputs[RESET_INPUT + i].isConnected(); - currentResetTriggered = resetTriggers[i].process(inputs[RESET_INPUT+i].getVoltage() / 2.f); + currentResetTriggered = resetTriggers[i].process(inputs[RESET_INPUT + i].getVoltage() / 2.f); currentTriggerIsHigh = clockTriggers[i].isHigh(); currentTriggerClocked = clockTriggers[i].process(inputs[CLOCK_INPUT + i].getVoltage()); currentManualResetClicked = manualResetTriggers[i].process(params[INDIVIDUAL_RESET_PARAM + i].getValue()); - if(this->laundrySequences[i].numSteps > 0) { + if (this->laundrySequences[i].numSteps > 0) { if (inputs[CLOCK_INPUT + i].isConnected()) { - if(currentTriggerClocked || globalManualClockClicked) { + if (currentTriggerClocked || globalManualClockClicked) { incrementInternalStep(i); activeStep[i] = (this->laundrySequences[i].peekWorkingStep() == 1); atLastStepAfterIncrement = this->laundrySequences[i].atLastStep(); - if(atLastStepAfterIncrement) checkIfShouldChange(i); + if (atLastStepAfterIncrement) checkIfShouldChange(i); } } else { @@ -285,31 +249,31 @@ void ComputerscareLaundrySoup::process(const ProcessArgs &args) { incrementInternalStep(i); activeStep[i] = (this->laundrySequences[i].peekWorkingStep() == 1); atLastStepAfterIncrement = this->laundrySequences[i].atLastStep(); - if(atLastStepAfterIncrement) checkIfShouldChange(i); + if (atLastStepAfterIncrement) checkIfShouldChange(i); } } atFirstStep = (this->laundrySequences[i].readHead == 0); - if(globalManualResetClicked || currentManualResetClicked) { - setChangeImminent(i,true); + if (globalManualResetClicked || currentManualResetClicked) { + setChangeImminent(i, true); checkIfShouldChange(i); resetOneOfThem(i); } - if( (currentResetActive && currentResetTriggered) || (!currentResetActive && globalResetTriggered)) { - - setChangeImminent(i,false); + if ( (currentResetActive && currentResetTriggered) || (!currentResetActive && globalResetTriggered)) { + + setChangeImminent(i, false); checkIfShouldChange(i); resetOneOfThem(i); } else { - if(atFirstStep && !currentResetActive && !inputs[GLOBAL_RESET_INPUT].isConnected()) { + if (atFirstStep && !currentResetActive && !inputs[GLOBAL_RESET_INPUT].isConnected()) { //checkIfShouldChange(i); } } } - if(inputs[CLOCK_INPUT + i].isConnected()) { + if (inputs[CLOCK_INPUT + i].isConnected()) { outputs[TRG_OUTPUT + i].setVoltage((currentTriggerIsHigh && activeStep[i]) ? 10.0f : 0.0f); outputs[FIRST_STEP_OUTPUT + i].setVoltage((currentTriggerIsHigh && atFirstStep) ? 10.f : 0.0f); } @@ -319,78 +283,222 @@ void ComputerscareLaundrySoup::process(const ProcessArgs &args) { } } } +struct LaundryTF2 : ComputerscareTextField +{ + ComputerscareLaundrySoup *module; + int fontSize = 16; + int rowIndex = 0; + bool inError = false; -void MyTextField::onTextChange() { - std::string value = module->textFields[this->rowIndex]->text; - LaundrySoupSequence lss = LaundrySoupSequence(value); - - if(!lss.inError && matchParens(value)) { - module->textFields[this->rowIndex]->inError=false; - module->setNextAbsoluteSequence(this->rowIndex); - module->updateDisplayBlink(this->rowIndex); + LaundryTF2(int i) + { + rowIndex=i; + ComputerscareTextField(); + }; + void draw(const DrawArgs &args) override + { + if (module) + { + std::string value = text.c_str(); + if (value != module->currentFormula[rowIndex]) + { + printf("diff %i, %s\n",rowIndex,text.c_str()); + LaundrySoupSequence lss = LaundrySoupSequence(value); + + if (!lss.inError && matchParens(value)) { + inError=false; + module->currentFormula[rowIndex] = value; + module->setNextAbsoluteSequence(this->rowIndex); + //module->updateDisplayBlink(rowIndex); + } + else { + printf("in error %i\n",index); + inError = true; + } + //module->setQuant(); + } + } + ComputerscareTextField::draw(args); } - else { - module->textFields[this->rowIndex]->inError=true; + + //void draw(const DrawArgs &args) override; + //int getTextPosition(math::Vec mousePos) override; +}; +/*struct LaundryTextField : LedDisplayTextField +{ + ComputerscareLaundrySoup *module; + std::shared_ptr<Font> font; + math::Vec textOffset; + NVGcolor color; + int fontSize = 16; + int rowIndex = 0; + bool inError = false; + void onEnter(const event::Enter &e) override; + LaundryTextField(int index) + { + rowIndex = index; + LedDisplayTextField(); + }; + void draw(const DrawArgs &args) override + { + if (module) + { + std::string value = text.c_str(); + if (text.c_str() != module->textFields[this->rowIndex]->text) + { + LaundrySoupSequence lss = LaundrySoupSequence(value); + // module->currentFormula = text.c_str(); + // module->setQuant(); + if (!lss.inError && matchParens(value)) { + //module->textFields[this->rowIndex]->inError = false; + //module->setNextAbsoluteSequence(this->rowIndex); + //module->updateDisplayBlink(this->rowIndex); + } + else { + //module->textFields[this->rowIndex]->inError = true; + } + } + LedDisplayTextField::draw(args); + } + } -} + //void draw(const DrawArgs &args) override; + //int getTextPosition(math::Vec mousePos) override; +}; +void LaundryTextField::onEnter(const event::Enter &e) { + module->setNextAbsoluteSequence(rowIndex); + //module->setQuant(); +}*/ +struct LaundrySmallDisplay : SmallLetterDisplay +{ + ComputerscareLaundrySoup *module; + int type; + int index; + LaundrySmallDisplay(int i) + { + index=i; + SmallLetterDisplay(); + }; + void draw(const DrawArgs &args) + { + //this->setNumDivisionsString(); + if (module) + { + value = module->getDisplayString(index); + SmallLetterDisplay::draw(args); + } + } + +}; struct ComputerscareLaundrySoupWidget : ModuleWidget { double verticalSpacing = 18.4; int verticalStart = 22; ComputerscareLaundrySoupWidget(ComputerscareLaundrySoup *module) { - setModule(module); - setPanel(APP->window->loadSvg(asset::plugin(plugin, "res/ComputerscareLaundrySoupPanel.svg"))); + setModule(module); + setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareLaundrySoupPanel.svg"))); //global clock input - addInput(Port::create<InPort>(mm2px(Vec(2 , 0)), Port::INPUT, module, ComputerscareLaundrySoup::GLOBAL_CLOCK_INPUT)); + addInput(createInput<InPort>(mm2px(Vec(2 , 0)), module, ComputerscareLaundrySoup::GLOBAL_CLOCK_INPUT)); //global reset input - addInput(Port::create<InPort>(mm2px(Vec(12 , 0)), Port::INPUT, module, ComputerscareLaundrySoup::GLOBAL_RESET_INPUT)); - - addParam(ParamWidget::create<ComputerscareClockButton>(mm2px(Vec(2 , 8)), module, ComputerscareLaundrySoup::MANUAL_CLOCK_PARAM, 0.0, 1.0, 0.0)); - addParam(ParamWidget::create<ComputerscareResetButton>(mm2px(Vec(12 , 8)), module, ComputerscareLaundrySoup::MANUAL_RESET_PARAM, 0.0, 1.0, 0.0)); - - for(int i = 0; i < numFields; i++) { + addInput(createInput<InPort>(mm2px(Vec(12 , 0)), module, ComputerscareLaundrySoup::GLOBAL_RESET_INPUT)); + + + // addParam(createParam<ComputerscareClockButton>(Vec(2, 321), module, ComputerscareDebug::MANUAL_TRIGGER)); + + addParam(createParam<ComputerscareClockButton>(mm2px(Vec(2 , 8)), module, ComputerscareLaundrySoup::MANUAL_CLOCK_PARAM)); + addParam(createParam<ComputerscareResetButton>(mm2px(Vec(12 , 8)), module, ComputerscareLaundrySoup::MANUAL_RESET_PARAM)); + + for (int i = 0; i < numFields; i++) { //first-step output - addOutput(Port::create<OutPort>(mm2px(Vec(42 , verticalStart + verticalSpacing*i - 11)), Port::OUTPUT, module, ComputerscareLaundrySoup::FIRST_STEP_OUTPUT + i)); + addOutput(createOutput<OutPort>(mm2px(Vec(42 , verticalStart + verticalSpacing * i - 11)), module, ComputerscareLaundrySoup::FIRST_STEP_OUTPUT + i)); //individual output - addOutput(Port::create<OutPort>(mm2px(Vec(54 , verticalStart + verticalSpacing*i - 11)), Port::OUTPUT, module, ComputerscareLaundrySoup::TRG_OUTPUT + i)); + addOutput(createOutput<OutPort>(mm2px(Vec(54 , verticalStart + verticalSpacing * i - 11)), module, ComputerscareLaundrySoup::TRG_OUTPUT + i)); //individual clock input - addInput(Port::create<InPort>(mm2px(Vec(2, verticalStart + verticalSpacing*i-10)), Port::INPUT, module, ComputerscareLaundrySoup::CLOCK_INPUT + i)); + addInput(createInput<InPort>(mm2px(Vec(2, verticalStart + verticalSpacing * i - 10)), module, ComputerscareLaundrySoup::CLOCK_INPUT + i)); //individual reset input - addInput(Port::create<InPort>(mm2px(Vec(12, verticalStart + verticalSpacing*i-10)), Port::INPUT, module, ComputerscareLaundrySoup::RESET_INPUT + i)); - - //sequence input field - textField = Widget::create<MyTextField>(mm2px(Vec(1, verticalStart + verticalSpacing*i))); - textField->setModule(module); - textField->box.size = mm2px(Vec(63, 7)); - textField->rowIndex = i; - textField->multiline = false; - textField->color = nvgRGB(0xC0, 0xE7, 0xDE); - addChild(textField); - module->textFields[i] = textField; + addInput(createInput<InPort>(mm2px(Vec(12, verticalStart + verticalSpacing * i - 10)), module, ComputerscareLaundrySoup::RESET_INPUT + i)); + + + /* textFieldTemp = createWidget<LaundryTF2>(mm2px(Vec(1, verticalStart + verticalSpacing * i))); + textFieldTemp->module = module; + textFieldTemp->box.size = mm2px(Vec(44, 7)); + textFieldTemp->multiline = false; + textFieldTemp->color = nvgRGB(0xC0, 0xE7, 0xDE); + textFieldTemp->text = ""; + textFieldTemp->rowIndex = i; + module->textFields[i] = textFieldTemp; + textFieldTemp->module = module; + addChild(textFieldTemp);*/ + textFieldTemp = new LaundryTF2(i); + textFieldTemp->box.pos = mm2px(Vec(1, verticalStart + verticalSpacing * i)); + textFieldTemp->module = module; + textFieldTemp->box.size = mm2px(Vec(44, 7)); + textFieldTemp->multiline = false; + textFieldTemp->color = nvgRGB(0xC0, 0xE7, 0xDE); + textFieldTemp->text = ""; + + laundryTextFields[i] = textFieldTemp; + addChild(textFieldTemp); + // active / total steps display - smallLetterDisplay = new SmallLetterDisplay(); - smallLetterDisplay->box.pos = mm2px(Vec(22,verticalStart - 9.2 +verticalSpacing*i)); + smallLetterDisplay = new LaundrySmallDisplay(i); + smallLetterDisplay->box.pos = mm2px(Vec(22, verticalStart - 9.2 + verticalSpacing * i)); smallLetterDisplay->box.size = Vec(60, 30); smallLetterDisplay->value = std::to_string(3); smallLetterDisplay->baseColor = COLOR_COMPUTERSCARE_LIGHT_GREEN; + smallLetterDisplay->module=module; addChild(smallLetterDisplay); - module->smallLetterDisplays[i] = smallLetterDisplay; + //module->smallLetterDisplays[i] = smallLetterDisplay; - addParam(ParamWidget::create<ComputerscareInvisibleButton>(mm2px(Vec(20,verticalStart - 9.2 +verticalSpacing*i)), module, ComputerscareLaundrySoup::INDIVIDUAL_RESET_PARAM + i, 0.0, 1.0, 0.0)); + addParam(createParam<ComputerscareInvisibleButton>(mm2px(Vec(20, verticalStart - 9.2 + verticalSpacing * i)), module, ComputerscareLaundrySoup::INDIVIDUAL_RESET_PARAM + i)); } + + laundry = module; module->onCreate(); } - MyTextField* textField; - SmallLetterDisplay* smallLetterDisplay; + json_t *toJson() override + { + json_t *rootJ = ModuleWidget::toJson(); + + json_t *sequencesJ = json_array(); + for (int i = 0; i < numFields; i++) { + json_t *sequenceJ = json_string(laundryTextFields[i]->text.c_str()); + json_array_append_new(sequencesJ, sequenceJ); + } + json_object_set_new(rootJ, "sequences", sequencesJ); + + return rootJ; + } + + void fromJson(json_t *rootJ) override + { + + ModuleWidget::fromJson(rootJ); + json_t *sequencesJ = json_object_get(rootJ, "sequences"); + if (sequencesJ) { + for (int i = 0; i < numFields; i++) { + + json_t *sequenceJ = json_array_get(sequencesJ, i); + if (sequenceJ) + laundryTextFields[i]->text = json_string_value(sequenceJ); + } + } + } + + ComputerscareLaundrySoup *laundry; + + LaundryTF2 *textFieldTemp; + LaundryTF2 *laundryTextFields[numFields]; + LaundrySmallDisplay* smallLetterDisplay; }; -Model *modelComputerscareLaundrySoup = Model::create<ComputerscareLaundrySoup, ComputerscareLaundrySoupWidget>("computerscare", "computerscare-laundry-soup", "Laundry Soup", SEQUENCER_TAG); +Model *modelComputerscareLaundrySoup = createModel<ComputerscareLaundrySoup, ComputerscareLaundrySoupWidget>("computerscare-laundry-soup"); diff --git a/src/ComputerscarePatchSequencer.cpp b/src/ComputerscarePatchSequencer.cpp @@ -207,7 +207,7 @@ struct ComputerscarePatchSequencer : Module { void ComputerscarePatchSequencer::process(const ProcessArgs &args) { int numStepsKnobPosition = (int) clamp(roundf(params[STEPS_PARAM].getValue()), 1.0f, 16.0f); - int channels[10] = {0}; + //int channels[10] = {0}; for ( int j = 0 ; j < 10 ; j++) {