You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
13KB

  1. #include "dsp/digital.hpp"
  2. #include "util/math.hpp"
  3. #include "qwelk.hpp"
  4. #define CHANNELS 8
  5. namespace rack_plugin_Qwelk {
  6. struct ModuleChaos : Module {
  7. enum ParamIds {
  8. PARAM_SCAN,
  9. PARAM_STEP,
  10. PARAM_CELL,
  11. NUM_PARAMS = PARAM_CELL + CHANNELS * 2
  12. };
  13. enum InputIds {
  14. INPUT_SCAN,
  15. INPUT_STEP,
  16. INPUT_RULE,
  17. INPUT_TRIG = INPUT_RULE + CHANNELS,
  18. NUM_INPUTS = INPUT_TRIG + CHANNELS,
  19. };
  20. enum OutputIds {
  21. OUTPUT_COUNT_A,
  22. OUTPUT_NUMBER_A,
  23. OUTPUT_COUNT_B,
  24. OUTPUT_NUMBER_B,
  25. OUTPUT_COUNT_AND,
  26. OUTPUT_NUMBER_AND,
  27. OUTPUT_COUNT_XOR,
  28. OUTPUT_NUMBER_XOR,
  29. OUTPUT_COUNT_OR,
  30. OUTPUT_NUMBER_OR,
  31. OUTPUT_GATE_A,
  32. OUTPUT_GATE_B = OUTPUT_GATE_A + CHANNELS,
  33. OUTPUT_GATE_XOR = OUTPUT_GATE_B + CHANNELS,
  34. OUTPUT_GATE_OR = OUTPUT_GATE_XOR + CHANNELS,
  35. OUTPUT_GATE_AND = OUTPUT_GATE_OR + CHANNELS,
  36. NUM_OUTPUTS = OUTPUT_GATE_AND + CHANNELS
  37. };
  38. enum LightIds {
  39. LIGHT_POS_SCAN,
  40. LIGHT_NEG_SCAN,
  41. LIGHT_STEP,
  42. LIGHT_MUTE,
  43. NUM_LIGHTS = LIGHT_MUTE + CHANNELS * 2
  44. };
  45. int fun = 0;
  46. int scan = 1;
  47. int scan_sign = 0;
  48. SchmittTrigger trig_step_input;
  49. SchmittTrigger trig_step_manual;
  50. SchmittTrigger trig_scan_input;
  51. SchmittTrigger trig_scan_manual;
  52. SchmittTrigger trig_cells[CHANNELS*2];
  53. SchmittTrigger trig_cells_input[CHANNELS];
  54. int states[CHANNELS*2] {};
  55. const float output_volt = 5.0;
  56. const float output_volt_uni = output_volt * 2;
  57. ModuleChaos() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  58. void step() override;
  59. json_t *toJson() override {
  60. json_t *rootJ = json_object();
  61. json_object_set_new(rootJ, "scan", json_integer(scan));
  62. json_object_set_new(rootJ, "fun", json_integer(fun));
  63. json_t *statesJ = json_array();
  64. for (int i = 0; i < CHANNELS*2; i++) {
  65. json_t *stateJ = json_integer(states[i]);
  66. json_array_append_new(statesJ, stateJ);
  67. }
  68. json_object_set_new(rootJ, "states", statesJ);
  69. return rootJ;
  70. }
  71. void fromJson(json_t *rootJ) override {
  72. json_t *scanJ = json_object_get(rootJ, "scan");
  73. if (scanJ)
  74. scan = json_integer_value(scanJ);
  75. json_t *funJ = json_object_get(rootJ, "fun");
  76. if (funJ)
  77. fun = json_integer_value(funJ);
  78. // gates
  79. json_t *statesJ = json_object_get(rootJ, "states");
  80. if (statesJ) {
  81. for (int i = 0; i < 8; i++) {
  82. json_t *gateJ = json_array_get(statesJ, i);
  83. if (gateJ)
  84. states[i] = json_integer_value(gateJ);
  85. }
  86. }
  87. }
  88. void reset() override {
  89. fun = 0;
  90. scan = 1;
  91. for (int i = 0; i < CHANNELS * 2; i++)
  92. states[i] = 0;
  93. }
  94. void randomize() override {
  95. scan = (randomUniform() > 0.5) ? 1 : -1;
  96. for (int i = 0; i < CHANNELS; i++)
  97. states[i] = (randomUniform() > 0.5);
  98. }
  99. };
  100. void ModuleChaos::step()
  101. {
  102. int nextstep = 0;
  103. if (trig_step_manual.process(params[PARAM_STEP].value)
  104. || trig_step_input.process(inputs[INPUT_STEP].value))
  105. nextstep = 1;
  106. // determine scan direction
  107. int scan_input_sign = (int)sgn(inputs[INPUT_SCAN].normalize(scan));
  108. if (scan_input_sign != scan_sign)
  109. scan = scan_sign = scan_input_sign;
  110. // manual tinkering with step?
  111. if (trig_scan_manual.process(params[PARAM_SCAN].value))
  112. scan *= -1;
  113. if (nextstep) {
  114. int rule = 0;
  115. // read rule from inputs
  116. for (int i = 0; i < CHANNELS; ++i)
  117. if (inputs[INPUT_RULE + i].active && inputs[INPUT_RULE + i].value > 0.0)
  118. rule |= 1 << i;
  119. // copy prev state to output cells
  120. for (int i = 0; i < CHANNELS; ++i)
  121. states[CHANNELS + i] = states[i];
  122. // determine the next gen
  123. for (int i = 0; i < CHANNELS; ++i) {
  124. int sum = 0;
  125. int tl = i == 0 ? CHANNELS - 1 : i - 1;
  126. int tm = i;
  127. int tr = i < CHANNELS - 1 ? i + (1 - fun): 0;
  128. sum |= states[CHANNELS + tr] ? (1 << 0) : 0;
  129. sum |= states[CHANNELS + tm] ? (1 << 1) : 0;
  130. sum |= states[CHANNELS + tl] ? (1 << 2) : 0;
  131. states[i] = (rule & (1 << sum)) != 0 ? 1 : 0;
  132. }
  133. }
  134. // handle manual tinkering with the state
  135. for (int i = 0; i < CHANNELS * 2; ++i)
  136. if (trig_cells[i].process(params[PARAM_CELL + i].value))
  137. states[i] ^= 1;
  138. // input trigs
  139. for (int i = 0; i < CHANNELS; ++i)
  140. if (trig_cells_input[i].process(inputs[INPUT_TRIG + i].value)
  141. && inputs[INPUT_TRIG + i].value > 0)
  142. states[i] = 1;
  143. int count_a = 0, count_b = 0, count_and = 0, count_xor = 0, count_or = 0,
  144. val_a = 0, val_b = 0, val_and = 0, val_xor = 0, val_or = 0;
  145. for (int i = 0; i < CHANNELS; ++i) {
  146. int bit = scan >= 0 ? i : (CHANNELS - 1 - i);
  147. int ab_and = states[i] && states[i + CHANNELS];
  148. int ab_xor = 1 - (states[i] == states[i + CHANNELS]);
  149. int ab_or = states[i] || states[i + CHANNELS];
  150. count_a += states[i];
  151. count_b += states[i + CHANNELS];
  152. count_and += ab_and;
  153. count_xor += ab_xor;
  154. count_or += ab_or;
  155. if (states[i] ) val_a |= 1 << bit;
  156. if (states[CHANNELS + i]) val_b |= 1 << bit;
  157. if (ab_and ) val_and |= 1 << bit;
  158. if (ab_xor ) val_xor |= 1 << bit;
  159. if (ab_or ) val_or |= 1 << bit;
  160. // individual gate output
  161. outputs[OUTPUT_GATE_A + i].value = states[i] ? output_volt : 0.0;
  162. outputs[OUTPUT_GATE_B + i].value = states[i + CHANNELS] ? output_volt : 0.0;
  163. outputs[OUTPUT_GATE_AND + i].value = ab_and ? output_volt : 0.0;
  164. outputs[OUTPUT_GATE_XOR + i].value = ab_xor ? output_volt : 0.0;
  165. outputs[OUTPUT_GATE_OR + i].value = ab_or ? output_volt : 0.0;
  166. }
  167. // number of LIVE cells
  168. outputs[OUTPUT_COUNT_A].value = ((float)count_a / (float)CHANNELS) * output_volt_uni;
  169. outputs[OUTPUT_COUNT_B].value = ((float)count_b / (float)CHANNELS) * output_volt_uni;
  170. outputs[OUTPUT_COUNT_XOR].value = ((float)count_xor / (float)CHANNELS) * output_volt_uni;
  171. outputs[OUTPUT_COUNT_AND].value = ((float)count_and / (float)CHANNELS) * output_volt_uni;
  172. outputs[OUTPUT_COUNT_OR].value = ((float)count_or / (float)CHANNELS) * output_volt_uni;
  173. // the binary number LIVE cells represent
  174. outputs[OUTPUT_NUMBER_A].value = ((float)val_a / (float)((1 << CHANNELS) - 1)) * output_volt_uni;
  175. outputs[OUTPUT_NUMBER_B].value = ((float)val_b / (float)((1 << CHANNELS) - 1)) * output_volt_uni;
  176. outputs[OUTPUT_NUMBER_XOR].value = ((float)val_xor / (float)((1 << CHANNELS) - 1)) * output_volt_uni;
  177. outputs[OUTPUT_NUMBER_AND].value = ((float)val_and / (float)((1 << CHANNELS) - 1)) * output_volt_uni;
  178. outputs[OUTPUT_NUMBER_OR].value = ((float)val_or / (float)((1 << CHANNELS) - 1)) * output_volt_uni;
  179. // indicate step direction
  180. lights[LIGHT_POS_SCAN].setBrightness(scan < 0 ? 0.0 : 0.9);
  181. lights[LIGHT_NEG_SCAN].setBrightness(scan < 0 ? 0.9 : 0.0);
  182. // indicate next generation
  183. lights[LIGHT_STEP].setBrightness(trig_step_manual.isHigh() || trig_step_input.isHigh() ? 0.9 : 0.0);
  184. // blink according to state
  185. for (int i = 0; i < CHANNELS * 2; ++i)
  186. lights[LIGHT_MUTE + i].setBrightness(states[i] ? 0.9 : 0.0);
  187. }
  188. template <typename _BASE>
  189. struct MuteLight : _BASE {
  190. MuteLight()
  191. {
  192. this->box.size = mm2px(Vec(6, 6));
  193. }
  194. };
  195. struct WidgetChaos : ModuleWidget {
  196. WidgetChaos(ModuleChaos *module);
  197. Menu *createContextMenu() override;
  198. };
  199. WidgetChaos::WidgetChaos(ModuleChaos *module) : ModuleWidget(module) {
  200. setPanel(SVG::load(assetPlugin(plugin, "res/Chaos.svg")));
  201. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  202. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  203. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  204. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  205. const float ypad = 27.5;
  206. const float tlpy = 1.75;
  207. const float lghx = box.size.x / 3.0;
  208. const float tlpx = 2.25;
  209. const float dist = 25;
  210. float ytop = 55;
  211. addInput(Port::create<PJ301MPort>( Vec(lghx - dist * 3 , ytop - ypad ), Port::INPUT, module, ModuleChaos::INPUT_SCAN));
  212. addParam(ParamWidget::create<LEDBezel>( Vec(lghx - dist * 2 , ytop - ypad ), module, ModuleChaos::PARAM_SCAN, 0.0, 1.0, 0.0));
  213. addChild(ModuleLightWidget::create<MuteLight<GreenRedLight>>( Vec(lghx - dist * 2 + tlpx , ytop - ypad + tlpy ), module, ModuleChaos::LIGHT_POS_SCAN));
  214. ytop += ypad;
  215. addInput(Port::create<PJ301MPort>( Vec(lghx - dist * 3 , ytop - ypad ), Port::INPUT, module, ModuleChaos::INPUT_STEP));
  216. addParam(ParamWidget::create<LEDBezel>( Vec(lghx - dist * 2 , ytop - ypad ), module, ModuleChaos::PARAM_STEP, 0.0, 1.0, 0.0));
  217. addChild(ModuleLightWidget::create<MuteLight<GreenLight>>(Vec(lghx - dist * 2 + tlpx , ytop - ypad + tlpy ), module, ModuleChaos::LIGHT_STEP));
  218. for (int i = 0; i < CHANNELS; ++i) {
  219. addInput(Port::create<PJ301MPort>( Vec(lghx - dist * 3 , ytop + ypad * i ), Port::INPUT, module, ModuleChaos::INPUT_RULE + i));
  220. addInput(Port::create<PJ301MPort>( Vec(lghx - dist * 2 , ytop + ypad * i ), Port::INPUT, module, ModuleChaos::INPUT_TRIG + i));
  221. addParam(ParamWidget::create<LEDBezel>( Vec(lghx - dist , ytop + ypad * i ), module, ModuleChaos::PARAM_CELL + i, 0.0, 1.0, 0.0));
  222. addChild(ModuleLightWidget::create<MuteLight<GreenLight>>(Vec(lghx - dist + tlpx , ytop + ypad * i + tlpy), module, ModuleChaos::LIGHT_MUTE + i));
  223. addParam(ParamWidget::create<LEDBezel>( Vec(lghx , ytop + ypad * i ), module, ModuleChaos::PARAM_CELL + CHANNELS + i, 0.0, 1.0, 0.0));
  224. addChild(ModuleLightWidget::create<MuteLight<GreenLight>>(Vec(lghx + tlpx , ytop + ypad * i + tlpy), module, ModuleChaos::LIGHT_MUTE + CHANNELS + i));
  225. addOutput(Port::create<PJ301MPort>( Vec(lghx + dist , ytop + ypad * i ), Port::OUTPUT, module, ModuleChaos::OUTPUT_GATE_A + i));
  226. addOutput(Port::create<PJ301MPort>( Vec(lghx + dist * 2 , ytop + ypad * i ), Port::OUTPUT, module, ModuleChaos::OUTPUT_GATE_B + i));
  227. addOutput(Port::create<PJ301MPort>( Vec(lghx + dist * 3 , ytop + ypad * i ), Port::OUTPUT, module, ModuleChaos::OUTPUT_GATE_AND + i));
  228. addOutput(Port::create<PJ301MPort>( Vec(lghx + dist * 4 , ytop + ypad * i ), Port::OUTPUT, module, ModuleChaos::OUTPUT_GATE_XOR + i));
  229. addOutput(Port::create<PJ301MPort>( Vec(lghx + dist * 5 , ytop + ypad * i ), Port::OUTPUT, module, ModuleChaos::OUTPUT_GATE_OR + i));
  230. }
  231. const float output_y = ytop + ypad * CHANNELS;
  232. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist , output_y ), Port::OUTPUT, module, ModuleChaos::OUTPUT_NUMBER_A));
  233. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist , output_y + ypad ), Port::OUTPUT, module, ModuleChaos::OUTPUT_COUNT_A));
  234. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 2 , output_y ), Port::OUTPUT, module, ModuleChaos::OUTPUT_NUMBER_B));
  235. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 2 , output_y + ypad ), Port::OUTPUT, module, ModuleChaos::OUTPUT_COUNT_B));
  236. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 3 , output_y ), Port::OUTPUT, module, ModuleChaos::OUTPUT_NUMBER_AND));
  237. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 3 , output_y + ypad ), Port::OUTPUT, module, ModuleChaos::OUTPUT_COUNT_AND));
  238. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 4 , output_y ), Port::OUTPUT, module, ModuleChaos::OUTPUT_NUMBER_XOR));
  239. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 4 , output_y + ypad ), Port::OUTPUT, module, ModuleChaos::OUTPUT_COUNT_XOR));
  240. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 5 , output_y ), Port::OUTPUT, module, ModuleChaos::OUTPUT_NUMBER_OR));
  241. addOutput(Port::create<PJ301MPort>(Vec(lghx + dist * 5 , output_y + ypad ), Port::OUTPUT, module, ModuleChaos::OUTPUT_COUNT_OR));
  242. }
  243. struct MenuItemFun : MenuItem {
  244. ModuleChaos *chaos;
  245. void onAction(EventAction &e) override
  246. {
  247. chaos->fun ^= 1;
  248. }
  249. void step () override
  250. {
  251. rightText = (chaos->fun) ? "✔" : "";
  252. }
  253. };
  254. Menu *WidgetChaos::createContextMenu()
  255. {
  256. Menu *menu = ModuleWidget::createContextMenu();
  257. MenuLabel *spacer = new MenuLabel();
  258. menu->addChild(spacer);
  259. ModuleChaos *chaos = dynamic_cast<ModuleChaos *>(module);
  260. assert(chaos);
  261. MenuItemFun *item = new MenuItemFun();
  262. item->text = "FUN";
  263. item->chaos = chaos;
  264. menu->addChild(item);
  265. return menu;
  266. }
  267. } // namespace rack_plugin_Qwelk
  268. using namespace rack_plugin_Qwelk;
  269. RACK_PLUGIN_MODEL_INIT(Qwelk, Chaos) {
  270. Model *modelChaos = Model::create<ModuleChaos, WidgetChaos>(
  271. TOSTRING(SLUG), "Chaos", "Chaos", SEQUENCER_TAG);
  272. return modelChaos;
  273. }