#include "aepelzen.hpp" #include "dsp/digital.hpp" #include #define NUM_CHANNELS 4 struct Erwin : Module { enum ParamIds { CHANNEL_TRANSPOSE_PARAM, NOTE_PARAM = CHANNEL_TRANSPOSE_PARAM + NUM_CHANNELS, NUM_PARAMS = NOTE_PARAM + 12 }; enum InputIds { TRANSPOSE_INPUT, SEMI_INPUT, IN_INPUT, NUM_INPUTS = IN_INPUT + 4 }; enum OutputIds { OUT_OUTPUT, NUM_OUTPUTS = OUT_OUTPUT + 4 }; enum LightIds { NOTE_LIGHT, NUM_LIGHTS = NOTE_LIGHT + 12 }; Erwin() : Module( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { reset(); }; void step() override; json_t* toJson() override; void fromJson(json_t *rootJ) override; //float ratios[13] = {1.0, 16.0/15, 9.0/8, 6.0/5, 5.0/4, 4.0/3, 7.0/5, 3.0/2, 8.0/5, 5.0/3, 16.0/9, 15.0/8, 2.0}; bool noteState[12] = {}; int octave; int transposeOctave = 0; int transposeSemi = 0; float freq; SchmittTrigger noteTriggers[12]; }; json_t* Erwin::toJson() { json_t *rootJ = json_object(); // Note values json_t *gatesJ = json_array(); for (int i = 0; i < 12; i++) { json_t *gateJ = json_boolean(noteState[i]); json_array_append_new(gatesJ, gateJ); } json_object_set_new(rootJ, "notes", gatesJ); return rootJ; } void Erwin::fromJson(json_t *rootJ) { // Note values json_t *gatesJ = json_object_get(rootJ, "notes"); for (int i = 0; i < 12; i++) { json_t *gateJ = json_array_get(gatesJ, i); noteState[i] = !!json_boolean_value(gateJ); } } void Erwin::step() { for(int y=0;y=0;i--) { if(noteState[i]) { lastValidIndex = i; break; } } if(transposeSemi) { lastValidIndex = (lastValidIndex + transposeSemi); } outputs[OUT_OUTPUT + y].value = octave + lastValidIndex * 1/12.0 + transposeOctave; } // Note buttons for (int i = 0; i < 12; i++) { if (noteTriggers[i].process(params[NOTE_PARAM + i].value)) { noteState[i] = !noteState[i]; } lights[NOTE_LIGHT + i].value = (noteState[i] >= 1.0) ? 0.7 : 0; } } template struct MuteLight : BASE { MuteLight() { this->box.size = mm2px(Vec(6.0, 6.0)); } }; struct ErwinWidget : ModuleWidget { ErwinWidget(Erwin *module); }; ErwinWidget::ErwinWidget(Erwin *module) : ModuleWidget(module) { box.size = Vec(15*8, 380); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin,"res/Erwin.svg"))); addChild(panel); } addChild(Widget::create(Vec(15, 0))); addChild(Widget::create(Vec(box.size.x-30, 0))); addChild(Widget::create(Vec(15, 365))); addChild(Widget::create(Vec(box.size.x-30, 365))); addInput(Port::create(Vec(22.5, 42), Port::INPUT, module, Erwin::TRANSPOSE_INPUT)); addInput(Port::create(Vec(76, 42), Port::INPUT, module, Erwin::SEMI_INPUT)); for(int i=0;i<4;i++) { addOutput(Port::create(Vec(76, 235 + i*30), Port::OUTPUT, module, Erwin::OUT_OUTPUT + i)); addInput(Port::create(Vec(76, 100 +i*30), Port::INPUT, module, Erwin::IN_INPUT + i)); } addParam(ParamWidget::create(Vec(16, 90), module, Erwin::CHANNEL_TRANSPOSE_PARAM, -4, 4, 0)); addParam(ParamWidget::create(Vec(38, 90), module, Erwin::CHANNEL_TRANSPOSE_PARAM + 1, -4, 4, 0)); addParam(ParamWidget::create(Vec(16, 117.5), module, Erwin::CHANNEL_TRANSPOSE_PARAM + 2, -4, 4, 0)); addParam(ParamWidget::create(Vec(38, 117.5), module, Erwin::CHANNEL_TRANSPOSE_PARAM + 3, -4, 4, 0)); //Note buttons int white=0; int black = 0; for(int i=0; i<12; i++) { if (i == 1 || i == 3 || i == 6 || i == 8 || i == 10 ) { addParam(ParamWidget::create(Vec(10,311.5 - black*30), module, Erwin::NOTE_PARAM + i, 0.0, 1.0, 0.0)); addChild(ModuleLightWidget::create>(Vec(12, 313.5 - black*30), module, Erwin::NOTE_LIGHT+i)); black++; } else { if(i == 4) black++; addParam(ParamWidget::create(Vec(35,326.5 - white*30), module, Erwin::NOTE_PARAM + i, 0.0, 1.0, 0.0)); addChild(ModuleLightWidget::create>(Vec(37, 328.5 - white*30), module, Erwin::NOTE_LIGHT+i)); white++; } } } Model *modelErwin = Model::create("Aepelzens Modules", "Erwin", "Erwin", UTILITY_TAG);