//*********************************************************************************************** //Engineering Test 1 // //Based on code from the Fundamental and AudibleInstruments plugins by Andrew Belt //and graphics from the Component Library by Wes Milholen //See ./LICENSE.txt for all licenses //See ./res/fonts/ for font licenses // //Module concept by Marc Boulé //*********************************************************************************************** #include "ImpromptuModular.hpp" #include "dsp/digital.hpp" struct EngTest1 : Module { enum ParamIds { ENUMS(NOTETYPE_PARAMS, 5), ENUMS(STEP_PARAMS, 24), NUM_PARAMS }; enum InputIds { NUM_INPUTS }; enum OutputIds { NUM_OUTPUTS }; enum LightIds { ENUMS(NOTETYPE_LIGHTS, 5), ENUMS(STEP_LIGHTS, 24 * 2),// room for GreenRed NUM_LIGHTS }; // Need to save int panelTheme; int noteType;// 0 is full note, 1 is half note, 2 is quarter note, etc... uint8_t notes[24]; // No need to save SchmittTrigger noteTypeTriggers[5]; SchmittTrigger stepTriggers[24]; EngTest1() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { panelTheme = 0; for (int i = 0; i < 5; i++) noteTypeTriggers[i].reset(); for (int i = 0; i < 24; i++) stepTriggers[i].reset(); onReset(); } // widgets are not yet created when module is created (and when onReset() is called by constructor) // onReset() is also called when right-click initialization of module void onReset() override { noteType = 2; for (int i = 0; i < 24; i++) { notes[i] = (i / 6) * 6; } } // widgets randomized before onRandomize() is called void onRandomize() override { } json_t *toJson() override { json_t *rootJ = json_object(); return rootJ; } // widgets loaded before this fromJson() is called void fromJson(json_t *rootJ) override { } // Advances the module by 1 audio frame with duration 1.0 / engineGetSampleRate() void step() override { // Step buttons for (int i = 0; i < 24; i++) { if (stepTriggers[i].process(params[STEP_PARAMS + i].value)) { int count = 3 * (1 << (3 - noteType)); int j; for (j = 0; j < count; j++) { if ((i + j) >= 24) break; notes[i + j] = i; } if ((i + j) < 24) { int oldVal = notes[i + j]; int newVal = i + j; for (; j < 24; j++) {// j < 24 is safety if ((i + j) >= 24) break; if (notes[i + j] == oldVal) notes[i + j] = newVal; } } } } // Note type buttons for (int i = 0; i < 5; i++) { if (noteTypeTriggers[i].process(params[NOTETYPE_PARAMS + i].value)) { noteType = i; } } // Step lights bool isGreen = true; for (int i = 0; i < 24; i++) { if (i > 0 && notes[i] != notes[i-1]) isGreen = !isGreen; setGreenRed(STEP_LIGHTS + i * 2, isGreen ? 1.0f : 0.0f, !isGreen ? 1.0f : 0.0f); } // Note type lights for (int i = 0; i < 5; i++) lights[NOTETYPE_LIGHTS + i].value = (i == noteType ? 1.0f : 0.0f); }// step() void setGreenRed(int id, float green, float red) { lights[id + 0].value = green; lights[id + 1].value = red; } };// EngTest1 : module struct EngTest1Widget : ModuleWidget { EngTest1Widget(EngTest1 *module) : ModuleWidget(module) { // Main panel from Inkscape DynamicSVGPanel* panel = new DynamicSVGPanel(); panel->mode = &module->panelTheme; panel->addPanel(SVG::load(assetPlugin(plugin, "res/light/EngTest1.svg"))); panel->addPanel(SVG::load(assetPlugin(plugin, "res/dark/EngTest1_dark.svg"))); box.size = panel->box.size; addChild(panel); // Screws addChild(createDynamicScrew(Vec(15, 0), &module->panelTheme)); addChild(createDynamicScrew(Vec(15, 365), &module->panelTheme)); addChild(createDynamicScrew(Vec(panel->box.size.x-30, 0), &module->panelTheme)); addChild(createDynamicScrew(Vec(panel->box.size.x-30, 365), &module->panelTheme)); // ****** Top portion (2 switches and LED button array ****** static const int rowRuler0 = 65; static const int colRulerSteps = 15; static const int spacingSteps = 20; //static const int spacingSteps4 = 4; // Step LED buttons int posX = colRulerSteps; for (int x = 0; x < 24; x++) { addParam(ParamWidget::create(Vec(posX, rowRuler0 + 8 - 4.4f), module, EngTest1::STEP_PARAMS + x, 0.0f, 1.0f, 0.0f)); addChild(ModuleLightWidget::create>(Vec(posX + 4.4f, rowRuler0 + 8), module, EngTest1::STEP_LIGHTS + x * 2)); posX += spacingSteps; //if ((x + 1) % 4 == 0) //posX += spacingSteps4; } // Note type buttons static const int rowRuler1 = 160; static const int posLEDvsButton = 25; static const int spacingButtons = 40; static const int columnRulerMB1 = colRulerSteps + 10; for (int x = 0; x < 5; x++) { addChild(ModuleLightWidget::create>(Vec(columnRulerMB1 + x * spacingButtons + offsetMediumLight, rowRuler1 + offsetMediumLight - posLEDvsButton), module, EngTest1::NOTETYPE_LIGHTS + x)); addParam(createDynamicParam(Vec(columnRulerMB1 + x * spacingButtons + offsetCKD6b, rowRuler1 + offsetCKD6b), module, EngTest1::NOTETYPE_PARAMS + x, 0.0f, 1.0f, 0.0f, &module->panelTheme)); } } }; Model *modelEngTest1 = Model::create("Impromptu Modular", "Eng-Test-1", "??? - Eng-Test-1", BLANK_TAG); /*CHANGE LOG 0.6.10: created */