ComputerscareSolyPequencer.cpp (8074B)
1 #include "Computerscare.hpp" 2 3 struct ComputerscareSolyPequencer; 4 5 struct ComputerscareSolyPequencer : ComputerscarePolyModule { 6 int currentStep[16] = {0}; 7 int numSteps[16] = {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; 8 int clockChannels[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 9 int resetChannels[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 10 11 bool autoNumSteps = true; 12 rack::dsp::SchmittTrigger clockTriggers[16]; 13 rack::dsp::SchmittTrigger resetTriggers[16]; 14 15 rack::dsp::SchmittTrigger globalManualClockTrigger; 16 rack::dsp::SchmittTrigger globalManualResetTrigger; 17 18 19 ComputerscareSVGPanel* panelRef; 20 enum ParamIds { 21 MANUAL_RUN_BUTTON, 22 MANUAL_CLOCK_BUTTON, 23 MANUAL_RESET_BUTTON, 24 NUM_STEPS_AUTO_BUTTON, 25 NUM_STEPS_KNOB, 26 POLY_CHANNELS, 27 NUM_PARAMS 28 }; 29 enum InputIds { 30 POLY_INPUT, 31 CLOCK_INPUT, 32 RESET_INPUT, 33 RUN_INPUT, 34 NUM_STEPS_INPUT, 35 NUM_INPUTS 36 }; 37 enum OutputIds { 38 POLY_OUTPUT, 39 EOC_OUTPUT, 40 NUM_OUTPUTS 41 }; 42 enum LightIds { 43 NUM_LIGHTS 44 }; 45 46 47 ComputerscareSolyPequencer() { 48 49 config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); 50 configButton(MANUAL_CLOCK_BUTTON, "Manual Clock Advance"); 51 configButton(MANUAL_RESET_BUTTON, "Manual Reset"); 52 configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 16.f, "Poly Channels"); 53 54 getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false; 55 getParamQuantity(POLY_CHANNELS)->resetEnabled = false; 56 57 configInput(POLY_INPUT, "Main"); 58 configInput(CLOCK_INPUT, "Clock"); 59 configInput(RESET_INPUT, "Reset Trigger"); 60 61 configOutput(POLY_OUTPUT, "Main"); 62 configOutput(EOC_OUTPUT, "End of Cycle"); 63 } 64 void resetAll() { 65 for (int i = 0; i < 16; i++) { 66 currentStep[i] = 0; 67 } 68 } 69 void checkPoly() override { 70 int resetNum = inputs[RESET_INPUT].getChannels(); 71 int clockNum = inputs[CLOCK_INPUT].getChannels(); 72 int knobSetting = params[POLY_CHANNELS].getValue(); 73 if (knobSetting == 0) { 74 polyChannels = inputs[CLOCK_INPUT].isConnected() ? std::max(clockNum, resetNum) : 16; 75 } 76 else { 77 polyChannels = knobSetting; 78 } 79 for (int i = 0; i < 16; i++) { 80 clockChannels[i] = std::max(1, std::min(i + 1, clockNum)); 81 resetChannels[i] = std::max(1, std::min(i + 1, resetNum)); 82 } 83 outputs[POLY_OUTPUT].setChannels(polyChannels); 84 outputs[EOC_OUTPUT].setChannels(polyChannels); 85 } 86 void process(const ProcessArgs &args) override { 87 ComputerscarePolyModule::checkCounter(); 88 int numInputChannels = inputs[POLY_INPUT].getChannels(); 89 int numReset = inputs[RESET_INPUT].getChannels(); 90 int numClock = inputs[CLOCK_INPUT].getChannels(); 91 //int numOutputChannels = numClock > 0 ? numClock : 1; 92 bool globalClocked = globalManualClockTrigger.process(params[MANUAL_CLOCK_BUTTON].getValue()); 93 bool manualReset = globalManualResetTrigger.process(params[MANUAL_RESET_BUTTON].getValue()); 94 95 if (inputs[POLY_INPUT].isConnected()) { 96 bool currentClock[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 97 bool currentReset[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 98 bool isHigh[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 99 bool eoc[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 100 for (int i = 0; i < 16; i++) { 101 currentClock[i] = clockTriggers[i].process(inputs[CLOCK_INPUT].getVoltage(i)); 102 currentReset[i] = resetTriggers[i].process(inputs[RESET_INPUT].getVoltage(i)); 103 isHigh[i] = clockTriggers[i].isHigh(); 104 } 105 for (int i = 0; i < 16; i++) { 106 eoc[i] = (currentClock[clockChannels[i] - 1] && isHigh[clockChannels[i] - 1]) || (currentReset[resetChannels[i] - 1] && resetTriggers[resetChannels[i] - 1].isHigh()); 107 } 108 for (int j = 0; j < polyChannels; j++) { 109 if (globalClocked || currentClock[clockChannels[j] - 1]) { 110 currentStep[j]++; 111 if (autoNumSteps) { 112 currentStep[j] = currentStep[j] % numInputChannels; 113 } 114 else { 115 currentStep[j] = currentStep[j] % numSteps[j]; 116 } 117 118 119 } 120 if (numReset == 1 && currentReset[0]) { 121 currentStep[j] = 0; 122 } 123 else if (j <= numReset && currentReset[j]) { 124 currentStep[j] = 0; 125 } 126 } 127 for (int c = 0; c < polyChannels; c++) { 128 outputs[POLY_OUTPUT].setVoltage(inputs[POLY_INPUT].getVoltage(currentStep[c]), c); 129 outputs[EOC_OUTPUT].setVoltage(currentStep[c] == 0 && eoc[c] ? 10.f : 0.f, c); 130 } 131 132 } 133 if (manualReset) { 134 resetAll(); 135 } 136 137 138 } 139 140 }; 141 struct PequencerSmallDisplay : SmallLetterDisplay 142 { 143 ComputerscareSolyPequencer *module; 144 int ch; 145 PequencerSmallDisplay(int outputChannelNumber) 146 { 147 148 ch = outputChannelNumber; 149 SmallLetterDisplay(); 150 }; 151 void draw(const DrawArgs &args) 152 { 153 //this->setNumDivisionsString(); 154 if (module) 155 { 156 157 158 //std::string str = std::to_string(module->routing[ch]); 159 value = std::to_string(module->currentStep[ch]); 160 161 162 163 } 164 else { 165 value = std::to_string((random::u32() % 16)); 166 } 167 SmallLetterDisplay::draw(args); 168 } 169 170 }; 171 172 struct ComputerscareSolyPequencerWidget : ModuleWidget { 173 ComputerscareSolyPequencerWidget(ComputerscareSolyPequencer *module) { 174 175 setModule(module); 176 //setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareSolyPequencerPanel.svg"))); 177 box.size = Vec(4 * 15, 380); 178 { 179 ComputerscareSVGPanel *panel = new ComputerscareSVGPanel(); 180 panel->box.size = box.size; 181 panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareSolyPequencerPanel.svg"))); 182 addChild(panel); 183 184 } 185 186 addOutput(createOutput<PointingUpPentagonPort>(Vec(4, 56), module, ComputerscareSolyPequencer::POLY_OUTPUT)); 187 addOutput(createOutput<TinyJack>(Vec(40, 84), module, ComputerscareSolyPequencer::EOC_OUTPUT)); 188 189 190 channelWidget = new PolyOutputChannelsWidget(Vec(26, 56), module, ComputerscareSolyPequencer::POLY_CHANNELS); 191 addChild(channelWidget); 192 193 addLabeledKnob("Steps", 10, 124, module, 0, 0, 0); 194 stepNumberGrid(1, 230, 30, 15, module); 195 196 197 addInput(createInput<InPort>(Vec(20, 116), module, ComputerscareSolyPequencer::POLY_INPUT)); 198 199 200 addParam(createParam<ComputerscareClockButton>(Vec(8, 152), module, ComputerscareSolyPequencer::MANUAL_CLOCK_BUTTON)); 201 addInput(createInput<PointingUpPentagonPort>(Vec(8, 169), module, ComputerscareSolyPequencer::CLOCK_INPUT)); 202 203 addParam(createParam<ComputerscareResetButton>(Vec(32, 169), module, ComputerscareSolyPequencer::MANUAL_RESET_BUTTON)); 204 addInput(createInput<InPort>(Vec(30, 182), module, ComputerscareSolyPequencer::RESET_INPUT)); 205 206 207 } 208 void stepNumberGrid(int x, int y, int xspacing, int yspacing, ComputerscareSolyPequencer *module) { 209 for (int i = 0; i < 2; i++) { 210 for (int j = 0; j < 8; j++) { 211 psd = new PequencerSmallDisplay(i * 8 + j); 212 psd->box.size = Vec(10, 10); 213 psd->box.pos = Vec(x + i * xspacing , y + j * yspacing); 214 psd->fontSize = 18; 215 psd->textAlign = 18; 216 psd->textColor = nvgRGB(0x24, 0x44, 0x31); 217 psd->breakRowWidth = 20; 218 psd->module = module; 219 addChild(psd); 220 } 221 } 222 } 223 void addLabeledKnob(std::string label, int x, int y, ComputerscareSolyPequencer *module, int index, float labelDx, float labelDy) { 224 225 /*psd = new PequencerSmallDisplay(index); 226 psd->box.size = Vec(20, 20); 227 psd->box.pos = Vec(x - 2.5 , y + 1.f); 228 psd->fontSize = 26; 229 psd->textAlign = 18; 230 psd->textColor =nvgRGB(0x24, 0x44, 0x31); 231 psd->breakRowWidth = 20; 232 psd->module = module;*/ 233 234 235 outputChannelLabel = new SmallLetterDisplay(); 236 outputChannelLabel->box.size = Vec(5, 5); 237 outputChannelLabel->box.pos = Vec(x + labelDx, y - 12 + labelDy); 238 outputChannelLabel->fontSize = 14; 239 outputChannelLabel->textAlign = index < 8 ? 1 : 4; 240 outputChannelLabel->breakRowWidth = 15; 241 242 //outputChannelLabel->value = "hogman"; 243 244 //addParam(createParam<MediumDotSnapKnob>(Vec(x, y), module, ComputerscareSolyPequencer::KNOB + index)); 245 //addChild(psd); 246 addChild(outputChannelLabel); 247 248 } 249 250 PolyOutputChannelsWidget* channelWidget; 251 PequencerSmallDisplay* psd; 252 SmallLetterDisplay* outputChannelLabel; 253 }; 254 255 256 Model *modelComputerscareSolyPequencer = createModel<ComputerscareSolyPequencer, ComputerscareSolyPequencerWidget>("computerscare-soly-pequencer");