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.

220 lines
6.9KB

  1. #include "Fundamental.hpp"
  2. struct SEQ3 : Module {
  3. enum ParamIds {
  4. CLOCK_PARAM,
  5. RUN_PARAM,
  6. RESET_PARAM,
  7. STEPS_PARAM,
  8. ENUMS(ROW1_PARAM, 8),
  9. ENUMS(ROW2_PARAM, 8),
  10. ENUMS(ROW3_PARAM, 8),
  11. ENUMS(GATE_PARAM, 8),
  12. NUM_PARAMS
  13. };
  14. enum InputIds {
  15. CLOCK_INPUT,
  16. EXT_CLOCK_INPUT,
  17. RESET_INPUT,
  18. STEPS_INPUT,
  19. NUM_INPUTS
  20. };
  21. enum OutputIds {
  22. GATES_OUTPUT,
  23. ROW1_OUTPUT,
  24. ROW2_OUTPUT,
  25. ROW3_OUTPUT,
  26. ENUMS(GATE_OUTPUT, 8),
  27. NUM_OUTPUTS
  28. };
  29. enum LightIds {
  30. RUNNING_LIGHT,
  31. RESET_LIGHT,
  32. GATES_LIGHT,
  33. ENUMS(ROW_LIGHTS, 3),
  34. ENUMS(GATE_LIGHTS, 8),
  35. NUM_LIGHTS
  36. };
  37. bool running = true;
  38. dsp::SchmittTrigger clockTrigger;
  39. dsp::SchmittTrigger runningTrigger;
  40. dsp::SchmittTrigger resetTrigger;
  41. dsp::SchmittTrigger gateTriggers[8];
  42. /** Phase of internal LFO */
  43. float phase = 0.f;
  44. int index = 0;
  45. bool gates[8] = {};
  46. SEQ3() {
  47. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  48. params[CLOCK_PARAM].config(-2.0f, 6.0f, 2.0f);
  49. params[RUN_PARAM].config(0.0f, 1.0f, 0.0f);
  50. params[RESET_PARAM].config(0.0f, 1.0f, 0.0f);
  51. params[STEPS_PARAM].config(1.0f, 8.0f, 8.0f);
  52. for (int i = 0; i < 8; i++) {
  53. params[ROW1_PARAM + i].config(0.0f, 10.0f, 0.0f);
  54. params[ROW2_PARAM + i].config(0.0f, 10.0f, 0.0f);
  55. params[ROW3_PARAM + i].config(0.0f, 10.0f, 0.0f);
  56. params[GATE_PARAM + i].config(0.0f, 1.0f, 0.0f);
  57. }
  58. onReset();
  59. }
  60. void onReset() override {
  61. for (int i = 0; i < 8; i++) {
  62. gates[i] = true;
  63. }
  64. }
  65. void onRandomize() override {
  66. for (int i = 0; i < 8; i++) {
  67. gates[i] = (random::uniform() > 0.5f);
  68. }
  69. }
  70. json_t *dataToJson() override {
  71. json_t *rootJ = json_object();
  72. // running
  73. json_object_set_new(rootJ, "running", json_boolean(running));
  74. // gates
  75. json_t *gatesJ = json_array();
  76. for (int i = 0; i < 8; i++) {
  77. json_array_insert_new(gatesJ, i, json_integer((int) gates[i]));
  78. }
  79. json_object_set_new(rootJ, "gates", gatesJ);
  80. return rootJ;
  81. }
  82. void dataFromJson(json_t *rootJ) override {
  83. // running
  84. json_t *runningJ = json_object_get(rootJ, "running");
  85. if (runningJ)
  86. running = json_is_true(runningJ);
  87. // gates
  88. json_t *gatesJ = json_object_get(rootJ, "gates");
  89. if (gatesJ) {
  90. for (int i = 0; i < 8; i++) {
  91. json_t *gateJ = json_array_get(gatesJ, i);
  92. if (gateJ)
  93. gates[i] = !!json_integer_value(gateJ);
  94. }
  95. }
  96. }
  97. void setIndex(int index) {
  98. int numSteps = (int) clamp(std::round(params[STEPS_PARAM].value + inputs[STEPS_INPUT].value), 1.0f, 8.0f);
  99. phase = 0.f;
  100. this->index = index;
  101. if (this->index >= numSteps)
  102. this->index = 0;
  103. }
  104. void step() override {
  105. // Run
  106. if (runningTrigger.process(params[RUN_PARAM].value)) {
  107. running = !running;
  108. }
  109. bool gateIn = false;
  110. if (running) {
  111. if (inputs[EXT_CLOCK_INPUT].active) {
  112. // External clock
  113. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value)) {
  114. setIndex(index + 1);
  115. }
  116. gateIn = clockTrigger.isHigh();
  117. }
  118. else {
  119. // Internal clock
  120. float clockTime = std::pow(2.0f, params[CLOCK_PARAM].value + inputs[CLOCK_INPUT].value);
  121. phase += clockTime * APP->engine->getSampleTime();
  122. if (phase >= 1.0f) {
  123. setIndex(index + 1);
  124. }
  125. gateIn = (phase < 0.5f);
  126. }
  127. }
  128. // Reset
  129. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value)) {
  130. setIndex(0);
  131. }
  132. // Gate buttons
  133. for (int i = 0; i < 8; i++) {
  134. if (gateTriggers[i].process(params[GATE_PARAM + i].value)) {
  135. gates[i] = !gates[i];
  136. }
  137. outputs[GATE_OUTPUT + i].value = (running && gateIn && i == index && gates[i]) ? 10.0f : 0.0f;
  138. lights[GATE_LIGHTS + i].setBrightnessSmooth((gateIn && i == index) ? (gates[i] ? 1.f : 0.33) : (gates[i] ? 0.66 : 0.0));
  139. }
  140. // Outputs
  141. outputs[ROW1_OUTPUT].value = params[ROW1_PARAM + index].value;
  142. outputs[ROW2_OUTPUT].value = params[ROW2_PARAM + index].value;
  143. outputs[ROW3_OUTPUT].value = params[ROW3_PARAM + index].value;
  144. outputs[GATES_OUTPUT].value = (gateIn && gates[index]) ? 10.0f : 0.0f;
  145. lights[RUNNING_LIGHT].value = (running);
  146. lights[RESET_LIGHT].setBrightnessSmooth(resetTrigger.isHigh());
  147. lights[GATES_LIGHT].setBrightnessSmooth(gateIn);
  148. lights[ROW_LIGHTS].value = outputs[ROW1_OUTPUT].value / 10.0f;
  149. lights[ROW_LIGHTS + 1].value = outputs[ROW2_OUTPUT].value / 10.0f;
  150. lights[ROW_LIGHTS + 2].value = outputs[ROW3_OUTPUT].value / 10.0f;
  151. }
  152. };
  153. struct SEQ3Widget : ModuleWidget {
  154. SEQ3Widget(SEQ3 *module) {
  155. setModule(module);
  156. setPanel(SVG::load(asset::plugin(plugin, "res/SEQ3.svg")));
  157. addChild(createWidget<ScrewSilver>(Vec(15, 0)));
  158. addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 0)));
  159. addChild(createWidget<ScrewSilver>(Vec(15, 365)));
  160. addChild(createWidget<ScrewSilver>(Vec(box.size.x-30, 365)));
  161. addParam(createParam<RoundBlackKnob>(Vec(18, 56), module, SEQ3::CLOCK_PARAM));
  162. addParam(createParam<LEDButton>(Vec(60, 61-1), module, SEQ3::RUN_PARAM));
  163. addChild(createLight<MediumLight<GreenLight>>(Vec(64.4f, 64.4f), module, SEQ3::RUNNING_LIGHT));
  164. addParam(createParam<LEDButton>(Vec(99, 61-1), module, SEQ3::RESET_PARAM));
  165. addChild(createLight<MediumLight<GreenLight>>(Vec(103.4f, 64.4f), module, SEQ3::RESET_LIGHT));
  166. addParam(createParam<RoundBlackSnapKnob>(Vec(132, 56), module, SEQ3::STEPS_PARAM));
  167. addChild(createLight<MediumLight<GreenLight>>(Vec(179.4f, 64.4f), module, SEQ3::GATES_LIGHT));
  168. addChild(createLight<MediumLight<GreenLight>>(Vec(218.4f, 64.4f), module, SEQ3::ROW_LIGHTS));
  169. addChild(createLight<MediumLight<GreenLight>>(Vec(256.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 1));
  170. addChild(createLight<MediumLight<GreenLight>>(Vec(295.4f, 64.4f), module, SEQ3::ROW_LIGHTS + 2));
  171. static const float portX[8] = {20, 58, 96, 135, 173, 212, 250, 289};
  172. addInput(createInput<PJ301MPort>(Vec(portX[0]-1, 98), module, SEQ3::CLOCK_INPUT));
  173. addInput(createInput<PJ301MPort>(Vec(portX[1]-1, 98), module, SEQ3::EXT_CLOCK_INPUT));
  174. addInput(createInput<PJ301MPort>(Vec(portX[2]-1, 98), module, SEQ3::RESET_INPUT));
  175. addInput(createInput<PJ301MPort>(Vec(portX[3]-1, 98), module, SEQ3::STEPS_INPUT));
  176. addOutput(createOutput<PJ301MPort>(Vec(portX[4]-1, 98), module, SEQ3::GATES_OUTPUT));
  177. addOutput(createOutput<PJ301MPort>(Vec(portX[5]-1, 98), module, SEQ3::ROW1_OUTPUT));
  178. addOutput(createOutput<PJ301MPort>(Vec(portX[6]-1, 98), module, SEQ3::ROW2_OUTPUT));
  179. addOutput(createOutput<PJ301MPort>(Vec(portX[7]-1, 98), module, SEQ3::ROW3_OUTPUT));
  180. for (int i = 0; i < 8; i++) {
  181. addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 157), module, SEQ3::ROW1_PARAM + i));
  182. addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 198), module, SEQ3::ROW2_PARAM + i));
  183. addParam(createParam<RoundBlackKnob>(Vec(portX[i]-2, 240), module, SEQ3::ROW3_PARAM + i));
  184. addParam(createParam<LEDButton>(Vec(portX[i]+2, 278-1), module, SEQ3::GATE_PARAM + i));
  185. addChild(createLight<MediumLight<GreenLight>>(Vec(portX[i]+6.4f, 281.4f), module, SEQ3::GATE_LIGHTS + i));
  186. addOutput(createOutput<PJ301MPort>(Vec(portX[i]-1, 307), module, SEQ3::GATE_OUTPUT + i));
  187. }
  188. }
  189. };
  190. Model *modelSEQ3 = createModel<SEQ3, SEQ3Widget>("SEQ3");