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.

301 lines
8.6KB

  1. #include "Fundamental.hpp"
  2. #include "dsp/digital.hpp"
  3. struct SEQ3 : Module {
  4. enum ParamIds {
  5. CLOCK_PARAM,
  6. RUN_PARAM,
  7. RESET_PARAM,
  8. STEPS_PARAM,
  9. ROW1_PARAM,
  10. ROW2_PARAM = ROW1_PARAM + 8,
  11. ROW3_PARAM = ROW2_PARAM + 8,
  12. GATE_PARAM = ROW3_PARAM + 8,
  13. NUM_PARAMS = GATE_PARAM + 8
  14. };
  15. enum InputIds {
  16. CLOCK_INPUT,
  17. EXT_CLOCK_INPUT,
  18. RESET_INPUT,
  19. STEPS_INPUT,
  20. NUM_INPUTS
  21. };
  22. enum OutputIds {
  23. GATES_OUTPUT,
  24. ROW1_OUTPUT,
  25. ROW2_OUTPUT,
  26. ROW3_OUTPUT,
  27. GATE_OUTPUT,
  28. NUM_OUTPUTS = GATE_OUTPUT + 8
  29. };
  30. bool running = true;
  31. SchmittTrigger clockTrigger; // for external clock
  32. // For buttons
  33. SchmittTrigger runningTrigger;
  34. SchmittTrigger resetTrigger;
  35. SchmittTrigger gateTriggers[8];
  36. float phase = 0.0;
  37. int index = 0;
  38. bool gateState[8] = {};
  39. float stepLights[8] = {};
  40. enum GateMode {
  41. TRIGGER,
  42. RETRIGGER,
  43. CONTINUOUS,
  44. };
  45. GateMode gateMode = TRIGGER;
  46. PulseGenerator gatePulse;
  47. // Lights
  48. float runningLight = 0.0;
  49. float resetLight = 0.0;
  50. float gatesLight = 0.0;
  51. float rowLights[3] = {};
  52. float gateLights[8] = {};
  53. SEQ3() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
  54. void step() override;
  55. json_t *toJson() override {
  56. json_t *rootJ = json_object();
  57. // running
  58. json_object_set_new(rootJ, "running", json_boolean(running));
  59. // gates
  60. json_t *gatesJ = json_array();
  61. for (int i = 0; i < 8; i++) {
  62. json_t *gateJ = json_integer((int) gateState[i]);
  63. json_array_append_new(gatesJ, gateJ);
  64. }
  65. json_object_set_new(rootJ, "gates", gatesJ);
  66. // gateMode
  67. json_t *gateModeJ = json_integer((int) gateMode);
  68. json_object_set_new(rootJ, "gateMode", gateModeJ);
  69. return rootJ;
  70. }
  71. void fromJson(json_t *rootJ) override {
  72. // running
  73. json_t *runningJ = json_object_get(rootJ, "running");
  74. if (runningJ)
  75. running = json_is_true(runningJ);
  76. // gates
  77. json_t *gatesJ = json_object_get(rootJ, "gates");
  78. if (gatesJ) {
  79. for (int i = 0; i < 8; i++) {
  80. json_t *gateJ = json_array_get(gatesJ, i);
  81. if (gateJ)
  82. gateState[i] = !!json_integer_value(gateJ);
  83. }
  84. }
  85. // gateMode
  86. json_t *gateModeJ = json_object_get(rootJ, "gateMode");
  87. if (gateModeJ)
  88. gateMode = (GateMode)json_integer_value(gateModeJ);
  89. }
  90. void reset() override {
  91. for (int i = 0; i < 8; i++) {
  92. gateState[i] = false;
  93. }
  94. }
  95. void randomize() override {
  96. for (int i = 0; i < 8; i++) {
  97. gateState[i] = (randomf() > 0.5);
  98. }
  99. }
  100. };
  101. void SEQ3::step() {
  102. const float lightLambda = 0.075;
  103. // Run
  104. if (runningTrigger.process(params[RUN_PARAM].value)) {
  105. running = !running;
  106. }
  107. runningLight = running ? 1.0 : 0.0;
  108. bool nextStep = false;
  109. if (running) {
  110. if (inputs[EXT_CLOCK_INPUT].active) {
  111. // External clock
  112. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) {
  113. phase = 0.0;
  114. nextStep = true;
  115. }
  116. }
  117. else {
  118. // Internal clock
  119. float clockTime = powf(2.0, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  120. phase += clockTime / engineGetSampleRate();
  121. if (phase >= 1.0) {
  122. phase -= 1.0;
  123. nextStep = true;
  124. }
  125. }
  126. }
  127. // Reset
  128. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
  129. phase = 0.0;
  130. index = 8;
  131. nextStep = true;
  132. resetLight = 1.0;
  133. }
  134. if (nextStep) {
  135. // Advance step
  136. int numSteps = clampi(roundf(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1, 8);
  137. index += 1;
  138. if (index >= numSteps) {
  139. index = 0;
  140. }
  141. stepLights[index] = 1.0;
  142. gatePulse.trigger(1e-3);
  143. }
  144. resetLight -= resetLight / lightLambda / engineGetSampleRate();
  145. bool pulse = gatePulse.process(1.0 / engineGetSampleRate());
  146. // Gate buttons
  147. for (int i = 0; i < 8; i++) {
  148. if (gateTriggers[i].process(params[GATE_PARAM + i].value)) {
  149. gateState[i] = !gateState[i];
  150. }
  151. bool gateOn = (running && i == index && gateState[i]);
  152. if (gateMode == TRIGGER)
  153. gateOn = gateOn && pulse;
  154. else if (gateMode == RETRIGGER)
  155. gateOn = gateOn && !pulse;
  156. outputs[GATE_OUTPUT + i].value = gateOn ? 10.0 : 0.0;
  157. stepLights[i] -= stepLights[i] / lightLambda / engineGetSampleRate();
  158. gateLights[i] = gateState[i] ? 1.0 - stepLights[i] : stepLights[i];
  159. }
  160. // Rows
  161. float row1 = params[ROW1_PARAM + index].value;
  162. float row2 = params[ROW2_PARAM + index].value;
  163. float row3 = params[ROW3_PARAM + index].value;
  164. bool gatesOn = (running && gateState[index]);
  165. if (gateMode == TRIGGER)
  166. gatesOn = gatesOn && pulse;
  167. else if (gateMode == RETRIGGER)
  168. gatesOn = gatesOn && !pulse;
  169. // Outputs
  170. outputs[ROW1_OUTPUT].value = row1;
  171. outputs[ROW2_OUTPUT].value = row2;
  172. outputs[ROW3_OUTPUT].value = row3;
  173. outputs[GATES_OUTPUT].value = gatesOn ? 10.0 : 0.0;
  174. gatesLight = gatesOn ? 1.0 : 0.0;
  175. rowLights[0] = row1;
  176. rowLights[1] = row2;
  177. rowLights[2] = row3;
  178. }
  179. SEQ3Widget::SEQ3Widget() {
  180. SEQ3 *module = new SEQ3();
  181. setModule(module);
  182. box.size = Vec(15*22, 380);
  183. {
  184. SVGPanel *panel = new SVGPanel();
  185. panel->box.size = box.size;
  186. panel->setBackground(SVG::load(assetPlugin(plugin, "res/SEQ3.svg")));
  187. addChild(panel);
  188. }
  189. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  190. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  191. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  192. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  193. addParam(createParam<Davies1900hSmallBlackKnob>(Vec(18, 56), module, SEQ3::CLOCK_PARAM, -2.0, 6.0, 2.0));
  194. addParam(createParam<LEDButton>(Vec(60, 61-1), module, SEQ3::RUN_PARAM, 0.0, 1.0, 0.0));
  195. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(65, 65), &module->runningLight));
  196. addParam(createParam<LEDButton>(Vec(99, 61-1), module, SEQ3::RESET_PARAM, 0.0, 1.0, 0.0));
  197. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(104, 65), &module->resetLight));
  198. addParam(createParam<Davies1900hSmallBlackSnapKnob>(Vec(132, 56), module, SEQ3::STEPS_PARAM, 1.0, 8.0, 8.0));
  199. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(180, 65), &module->gatesLight));
  200. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(219, 65), &module->rowLights[0]));
  201. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(257, 65), &module->rowLights[1]));
  202. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(296, 65), &module->rowLights[2]));
  203. static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289};
  204. addInput(createInput<PJ301MPort>(Vec(portX[0]-1, 98), module, SEQ3::CLOCK_INPUT));
  205. addInput(createInput<PJ301MPort>(Vec(portX[1]-1, 98), module, SEQ3::EXT_CLOCK_INPUT));
  206. addInput(createInput<PJ301MPort>(Vec(portX[2]-1, 98), module, SEQ3::RESET_INPUT));
  207. addInput(createInput<PJ301MPort>(Vec(portX[3]-1, 98), module, SEQ3::STEPS_INPUT));
  208. addOutput(createOutput<PJ301MPort>(Vec(portX[4]-1, 98), module, SEQ3::GATES_OUTPUT));
  209. addOutput(createOutput<PJ301MPort>(Vec(portX[5]-1, 98), module, SEQ3::ROW1_OUTPUT));
  210. addOutput(createOutput<PJ301MPort>(Vec(portX[6]-1, 98), module, SEQ3::ROW2_OUTPUT));
  211. addOutput(createOutput<PJ301MPort>(Vec(portX[7]-1, 98), module, SEQ3::ROW3_OUTPUT));
  212. for (int i = 0; i < 8; i++) {
  213. addParam(createParam<Davies1900hSmallBlackKnob>(Vec(portX[i]-2, 157), module, SEQ3::ROW1_PARAM + i, 0.0, 6.0, 0.0));
  214. addParam(createParam<Davies1900hSmallBlackKnob>(Vec(portX[i]-2, 198), module, SEQ3::ROW2_PARAM + i, 0.0, 6.0, 0.0));
  215. addParam(createParam<Davies1900hSmallBlackKnob>(Vec(portX[i]-2, 240), module, SEQ3::ROW3_PARAM + i, 0.0, 6.0, 0.0));
  216. addParam(createParam<LEDButton>(Vec(portX[i]+2, 278-1), module, SEQ3::GATE_PARAM + i, 0.0, 1.0, 0.0));
  217. addChild(createValueLight<SmallLight<GreenValueLight>>(Vec(portX[i]+7, 282), &module->gateLights[i]));
  218. addOutput(createOutput<PJ301MPort>(Vec(portX[i]-1, 307), module, SEQ3::GATE_OUTPUT + i));
  219. }
  220. }
  221. struct SEQ3GateModeItem : MenuItem {
  222. SEQ3 *seq3;
  223. SEQ3::GateMode gateMode;
  224. void onAction() override {
  225. seq3->gateMode = gateMode;
  226. }
  227. void step() override {
  228. rightText = (seq3->gateMode == gateMode) ? "✔" : "";
  229. }
  230. };
  231. Menu *SEQ3Widget::createContextMenu() {
  232. Menu *menu = ModuleWidget::createContextMenu();
  233. MenuLabel *spacerLabel = new MenuLabel();
  234. menu->pushChild(spacerLabel);
  235. SEQ3 *seq3 = dynamic_cast<SEQ3*>(module);
  236. assert(seq3);
  237. MenuLabel *modeLabel = new MenuLabel();
  238. modeLabel->text = "Gate Mode";
  239. menu->pushChild(modeLabel);
  240. SEQ3GateModeItem *triggerItem = new SEQ3GateModeItem();
  241. triggerItem->text = "Trigger";
  242. triggerItem->seq3 = seq3;
  243. triggerItem->gateMode = SEQ3::TRIGGER;
  244. menu->pushChild(triggerItem);
  245. SEQ3GateModeItem *retriggerItem = new SEQ3GateModeItem();
  246. retriggerItem->text = "Retrigger";
  247. retriggerItem->seq3 = seq3;
  248. retriggerItem->gateMode = SEQ3::RETRIGGER;
  249. menu->pushChild(retriggerItem);
  250. SEQ3GateModeItem *continuousItem = new SEQ3GateModeItem();
  251. continuousItem->text = "Continuous";
  252. continuousItem->seq3 = seq3;
  253. continuousItem->gateMode = SEQ3::CONTINUOUS;
  254. menu->pushChild(continuousItem);
  255. return menu;
  256. }